1. Read in the data

Load the required packages

[1] "Seurat is loaded correctly"
[1] "viridis is loaded correctly"
[1] "ggpubr is loaded correctly"
[1] "cowplot is loaded correctly"
[1] "ggplot2bdc is loaded correctly"
[1] "patchwork is loaded correctly"

Import GTF file

This will be helpful later on. This contains annotations for each gene:

##Import gtf file:
gtf <- read.table("/Users/Andy/GCSKO/GCSKO_analysis_git/data/Pberghei.gtf", sep="\t", header = FALSE)
head(gtf)

*N.B.This was the .gtf file used for feature counting the data

Import Counts and Pheno files

## read in counts
counts <- read.delim("/Users/Andy/GCSKO/GCSKO_analysis_git/data/counts_2020.csv", sep = ",", stringsAsFactors = FALSE, row.names = 1)

## read in pheno
pheno <- read.delim("/Users/Andy/GCSKO/GCSKO_analysis_git/data/pheno_2020.csv", sep = ",", stringsAsFactors = FALSE)

## check dimensions of both
expected_number_of_cells <- ( 384 * 12)
paste("The expected number of cells is", expected_number_of_cells)
[1] "The expected number of cells is 4608"
paste("number of genes in counts", dim(counts)[1], "number of cells in counts", dim(counts)[2])
[1] "number of genes in counts 5250 number of cells in counts 4608"
paste("number of columns in counts", dim(pheno)[2], "number of cells in pheno", dim(pheno)[1])
[1] "number of columns in counts 98 number of cells in pheno 4608"
## make rownames the sample_id in pheno
rownames(pheno) <- pheno$sample_id

## check that the names are the same
paste("Are the names the same?")
[1] "Are the names the same?"
table((colnames(counts) %in% rownames(pheno)))

TRUE 
4608 

Remove Anopheles cells

These cells were included in one of the sequencing runs and are irrelevant.

## get rid of the cells by finding all the cells that have As in their species col
names_of_mosquito_cells <- rownames(pheno[(pheno$species == "As"), ])

## which gives
table(colnames(counts) %in% names_of_mosquito_cells)

FALSE  TRUE 
 4512    96 
## subset 
counts <- counts[,-which(colnames(counts) %in% names_of_mosquito_cells)]
pheno <- pheno[-(which(rownames(pheno) %in% names_of_mosquito_cells)), ]

## check dimensions
paste("number of genes in counts", dim(counts)[1], "number of cells in counts", dim(counts)[2])
[1] "number of genes in counts 5250 number of cells in counts 4512"
paste("number of columns in counts", dim(pheno)[2], "number of cells in pheno", dim(pheno)[1])
[1] "number of columns in counts 98 number of cells in pheno 4512"

Remove control cells:

## find all cells that are labelled as such
names_of_control_cells <- rownames(pheno[(pheno$is_control == "TRUE"), ])

## which gives
table(colnames(counts) %in% names_of_control_cells)

FALSE  TRUE 
 4386   126 
## subset 
counts <- counts[,-which(colnames(counts) %in% names_of_control_cells)]
pheno <- pheno[-(which(rownames(pheno) %in% names_of_control_cells)), ]

## check dimensions
paste("number of genes in counts", dim(counts)[1], "number of cells in counts", dim(counts)[2])
[1] "number of genes in counts 5250 number of cells in counts 4386"
paste("number of columns in counts", dim(pheno)[2], "number of cells in pheno", dim(pheno)[1])
[1] "number of columns in counts 98 number of cells in pheno 4386"

Remove 10 and 27

10 and 27 failed genotyping and so will be removed

## find all cells that are labelled as such
names_of_genotype_fail_cells <- rownames(pheno[(pheno$sub_identity_updated %in% c("GCSKO-10", "WT-10", "GCSKO-27")), ])

## which gives
table(colnames(counts) %in% names_of_genotype_fail_cells)

FALSE  TRUE 
 3732   654 
## subset 
counts <- counts[,-which(colnames(counts) %in% names_of_genotype_fail_cells)]
pheno <- pheno[-(which(rownames(pheno) %in% names_of_genotype_fail_cells)), ]

## check dimensions
paste("number of genes in counts", dim(counts)[1], "number of cells in counts", dim(counts)[2])
[1] "number of genes in counts 5250 number of cells in counts 3732"
paste("number of columns in counts", dim(pheno)[2], "number of cells in pheno", dim(pheno)[1])
[1] "number of columns in counts 98 number of cells in pheno 3732"

Filter non-genes out of counts

Filter out the QC columns contained in counts that do not correspond to genes

## since the datatable currently contains:
paste("The current counts table contains these non-gene rows:")
[1] "The current counts table contains these non-gene rows:"
rownames(counts[-(grep("PBANKA*", rownames(counts))), ])
[1] "__alignment_not_unique" "__ambiguous"           
[3] "__no_feature"           "__not_aligned"         
[5] "__too_low_aQual"       
## subset
# make a copy of counts just in case that info is useful in future analysis
counts_genes <- counts
# remove non-gene rows
counts <- counts[(grep("PBANKA*", rownames(counts))), ]
#check
paste("number of genes in counts", dim(counts)[1], "number of cells in counts", dim(counts)[2])
[1] "number of genes in counts 5245 number of cells in counts 3732"

This 5245 includes all types of genes:

## check size
paste("The dimensions of the GTF file are:")
[1] "The dimensions of the GTF file are:"
dim(gtf[-which(gtf$V3 == "CDS"),])
[1] 5245    9
## look at possible types of genes
paste("The types of genes in the dataframe are:")
[1] "The types of genes in the dataframe are:"
names(table(gtf$V3))
[1] "CDS"                    "mRNA"                  
[3] "ncRNA"                  "pseudogenic_transcript"
[5] "rRNA"                   "snoRNA"                
[7] "snRNA"                  "tRNA"                  

2. Filtering

set-up data

make seurat object

## make seurat object
ss2_mutants <- CreateSeuratObject(counts = counts, project = "GCSKO", min.cells = 0, min.features = 1, meta.data = pheno)
Feature names cannot have underscores ('_'), replacing with dashes ('-')
# n.b. cells must have at least 1 gene per cell because this causes problems downstream

## add experiment column to meta data:
ss2_mutants@meta.data$experiment <- "ss2_mutants"

## inspect object
ss2_mutants
An object of class Seurat 
5245 features across 3705 samples within 1 assay 
Active assay: RNA (5245 features, 0 variable features)
## how many genes are not detected at all?
paste(length(which(rowSums(as.matrix(ss2_mutants@assays$RNA@counts)) == 0)), " genes are not detected in any cell")
[1] "63  genes are not detected in any cell"
[1] "27  cells have zero counts"

Filtered Cells Plate Heatmap

set up data

## load in dplyr 
library(dplyr) #for mutating table

## make dataframe
df_platemap <- data.frame(well_name = pheno$well_name_R, cell_name = rownames(pheno), row.names = rownames(pheno))

## get cells that are filtered out
cells_kept <- which(rownames(df_platemap) %in% rownames(ss2_mutants@meta.data))

## make extra column in plotting df
df_platemap$colour <- "filtered_out"
df_platemap$colour[cells_kept] <- "passed_QC"

## inspect
head(df_platemap)

Make a table for each

table_platemap <- as.data.frame(table(df_platemap$well_name, df_platemap$colour))
names(table_platemap) <- c("well", "filtered", "frequency")

#make separate dfs
df_1 <- table_platemap[table_platemap$filtered == "filtered_out",]
df_2 <- table_platemap[table_platemap$filtered == "passed_QC",]

# merge them back together
table_platemap <- merge(df_1, df_2, by = "well", all = TRUE)

## remove the irrelevant rows and rename cols and rename rows
table_platemap <- table_platemap[ ,c(1,3,5)]
names(table_platemap) <- c("well", "filtered_out", "passed_QC")
table_platemap$well_name <- rownames(table_platemap)

## add A1?
#table_platemap[96,] <- c("A1", "0", "0")

## add cols for plotting
table_platemap$Row <- as.numeric(match(toupper(substr(table_platemap$well, 1, 1)), LETTERS))
table_platemap$Column <- as.numeric(substr(table_platemap$well, 2, 5))

Plot

## calculate a percentage
table_platemap$filtered_pc <- ((table_platemap$filtered_out)/(table_platemap$filtered_out + table_platemap$passed_QC))*100

for(i in seq(1,8)){
  table_platemap$Row_rev[table_platemap$Row == i] <- seq(8,1)[i]
}

## one way of manually colouring in points after
#+ scale_colour_manual(values=c(table_of_colors[1:2],c="green"))
## find wells where it's zero
zero_wells <- table_platemap$filtered_pc == 0
table_platemap$filtered_pc[zero_wells] <- NA

## plot
sample_map_no_reads <- ggplot(data=table_platemap, aes(x=Column, y=Row_rev)) +
  #set up the platemap layout
    geom_point(data=expand.grid(seq(1, 12), seq(1, 8)), aes(x=Var1, y=Var2), color="grey90", fill="white", shape=21, size=6) +
  #Change the shape and colour of points for a variable
    geom_point(aes(colour = filtered_pc)) +
  #change the colours
    scale_colour_viridis_c(guide = "colourbar", na.value="white") +
  ## diplay legend on bottom
    theme(legend.position="bottom") +
  #fix the ratio of coordinates
    coord_fixed(ratio=(13/12)/(9/8), xlim=c(0.5, 12.5), ylim=c(0.6, 8.4)) +
  # make into a plate plot
    theme_bdc_microtiter() +
  #add labels for the y axis
    scale_y_continuous(breaks = seq(1, 8), labels = LETTERS[1:8]) +
  #add labels for the x axis
    scale_x_continuous(position = "top", breaks=seq(1, 12)) +
  #Add a title and change label of fill
    labs(title="The position of cells with zero counts" , size = 6, colour = "percentage of cells in this well with zero counts") +
  #rotate legend guide because otherwise you can't see numbers:
    guides(fill = guide_colorbar(barwidth = 0.5, barheight = 10, title="Value"))

  



ggplot(data = table_platemap, aes(x = Column, y = Row)) +
geom_point(data = expand.grid(Column = seq(1,12), Row = seq(1,8)), color = "grey90", fill = "white", shape = 21, size = 8) +
geom_point(aes(color = filtered_pc), size = 9) +
labs(title = "Plate Layout for My Experiment", subtitle = "25 March 2016") +
coord_fixed(ratio = (13/12)/(9/8), xlim = c(0.5, 12.5), ylim = c(0.6, 8.4)) + theme_bdc_microtiter() + scale_x_continuous(position = "top", breaks = seq(1, 12))  +
theme(legend.position = "bottom") + guides(shape = guide_legend(override.aes = list(size = 3)),
color = guide_legend(override.aes = list(size = 3))) + scale_y_continuous(breaks = seq(1, 8), labels = LETTERS[1:8])






## print
sample_map_no_reads

## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/platemap_no_count.png", plot = sample_map_no_reads, device = "png", path = NULL, scale = 1, width = 10, height = 10, units = "cm", dpi = 300, limitsize = TRUE)


## to make scatterpie
##library("scatterpie") # needed for geom_scatterpie
## then use this rather than geom_point and colour by
##+geom_scatterpie(aes(x=Column, y=Row, group = well), data=table_platemap, cols=c("filtered_out", "passed_QC"), color=NA, alpha=.8)

Filter Mitochondrial (Figure S6)

Mitochondrial cell counts

## extract mitochondrial genes 
mito_genes <- gtf[which(gtf$V3 == "rRNA"),]$V9
mito_genes <- gsub(";.*","", gsub("gene_id ", "", mito_genes))
paste("These are the mitochondrial genes")
[1] "These are the mitochondrial genes"
head(mito_genes)
[1] "PBANKA_0521221" "PBANKA_0521241" "PBANKA_0521261" "PBANKA_0622921"
[5] "PBANKA_0622941" "PBANKA_0622961"
## make a percentage mitocondrial for each cell (this will work as long as you filter cells out with zero counts)
ss2_mutants <- PercentageFeatureSet(ss2_mutants, features = which(rownames(counts) %in% mito_genes), col.name = "percent.mt")

plot percentage mitochondrial

## plot for percentage of mitochondrial reads
v1 <- VlnPlot(object = ss2_mutants, features = "percent.mt", group.by = "identity_updated", pt.size = 0.01) + 
  ## add a line where we will filter 
  geom_hline(yintercept=20) +
  ## remove legend
  theme(legend.position = "none") +
  ## change labels
  labs(x = "Genotype", y = "% Mitochondrial Reads") +
  ## remove plot title
  theme(plot.title = element_blank())

## plot for percentage of mitochondrial reads
v2 <- VlnPlot(object = ss2_mutants, features = "percent.mt", group.by = "experiment", pt.size = 0.01) +
  geom_hline(yintercept=20) +
  ## remove legend
  theme(legend.position = "none") +
  ## fremove axis labels
  labs(x="", y = "") +
  ## remove axis elements
  theme(plot.title = element_blank(), axis.text.y = element_blank(),
        axis.ticks.y = element_blank()) +
  ## change label on bottom of plot
  scale_x_discrete(labels = "All cells")

## plot together
QC_mito_violin <- v1 + v2 + plot_layout(ncol = 2, nrow = 1, widths = c(4, 1), heights = c(2, 2))

## print
QC_mito_violin

## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/QC_mito_violin.png", plot = QC_mito_violin, device = "png", path = NULL, scale = 1, width = 15, height = 10, units = "cm", dpi = 300, limitsize = TRUE)

make a dataframe for plotting

df <- data.frame(nCount = log10(ss2_mutants@meta.data$nCount_RNA), nGenes = ss2_mutants@meta.data$nFeature_RNA, identity = ss2_mutants@meta.data$identity_updated, identity_gene = ss2_mutants@meta.data$identity_gene_updated, percent_mt = ss2_mutants@meta.data$percent.mt)

Where do mitchondrial poor cells lie?

## make extra col for filtered values:
filtered_out_cells <- which(df$percent_mt > 20) 

## plot
QC_mito_graph <- ggplot(df, aes(x = nCount, y = nGenes)) + 
  geom_point(alpha = 0.4) +
  scale_size(range = c(0.1,4)) +
  #geom_rug() + 
  scale_y_continuous(name = "Number of Detected Genes") + 
  scale_x_continuous(name = "log10(Number of Total Counts)") +
  scale_color_viridis(option = "D") +
  theme_pubr() +
  theme(legend.position = "bottom") +
  geom_vline(xintercept=3) +
  geom_hline(yintercept=220) +
  geom_hline(yintercept=3300) +
  #annotate selected points
  annotate("point", df$nCount[filtered_out_cells], df$nGenes[filtered_out_cells], size = 2, colour = "orange")

## add this to gemo_point if needed: aes(colour = percent_mt, size = percent_mt)

## print
QC_mito_graph

## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/QC_mito_graph.png", plot = QC_mito_graph, device = "png", path = NULL, scale = 1, width = 10, height = 10, units = "cm", dpi = 300, limitsize = TRUE)

## plot 1
plot1 <- FeatureScatter(ss2_mutants, feature1 = "nCount_RNA", feature2 = "percent.mt", pt.size = 0.01, group.by = "identity_updated")

## plot 2
plot2 <- FeatureScatter(ss2_mutants, feature1 = "nCount_RNA", feature2 = "nFeature_RNA", pt.size = 0.01, group.by = "identity_updated")

## plot together
plot1 + plot2

Filter poor quality cells

in the MCA paper: “Cells with fewer than 1000 genes per cell and 2500 reads per cell were removed from the liver-stage parasites, trophozoites, male and female gametocytes, ookinetes, ookinetes/oocysts, and oocyst stages. Cells with fewer than 500 genes per cell and 2500 reads per cell were removed from schizonts and injected sporozoites. Cells with fewer than 40 genes per cell and 1000 reads per cell were removed from merozoites, rings, and gland sporozoites (fig. S2 and table S1). Additionally, we removed genes from further analysis that were detected in fewer than two cells across the entire dataset. The final dataset contained 1787 high-quality single cells from 1982 sequenced cells and 5156 genes out of 5245 genes with annotated transcripts.”

so use: 1000 reads per cell & 40 genes per cell as absolute minimums

## plot main dotplot
plot1 <- ggplot(df, aes(x = nCount, y = nGenes, color = identity)) + 
  geom_point(aes(color = identity), size = 0.1) +
  geom_rug() + 
  scale_y_continuous(name = "Number of Detected Genes") + 
  scale_x_continuous(name = "log10(Number of Total Counts)") + 
  theme_pubr() +
  theme(legend.position = "bottom") +
  geom_vline(xintercept=3) +
  geom_hline(yintercept=220) +
  geom_hline(yintercept=3300)

## plot density plot x
dens1 <- ggplot(df, aes(x = nCount, fill = identity)) + 
  geom_density(alpha = 0.2) + 
  theme_void() + 
  theme(legend.position = "none")

## plot density plot y
dens2 <- ggplot(df, aes(x = nGenes, fill = identity)) + 
  geom_density(alpha = 0.2) + 
  theme_void() + 
  theme(legend.position = "none") + 
  coord_flip()

## plot together
QC_composite_plot <- dens1 + plot_spacer() + plot1 + dens2 + plot_layout(ncol = 2, nrow = 2, widths = c(4, 1), heights = c(1, 4))

## print
QC_composite_plot


## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/QC_composite_plot.png", plot = QC_composite_plot, device = "png", path = NULL, scale = 1, width = 20, height = 20, units = "cm", dpi = 300, limitsize = TRUE)

3. Analysis

Final filter

filter out cells

## subset
ss2_mutants_final <- subset(ss2_mutants, subset = nFeature_RNA > 220 & nFeature_RNA < 3300 & percent.mt < 20 & nCount_RNA > 1000)

## inspect resultant object
ss2_mutants_final
An object of class Seurat 
5245 features across 3031 samples within 1 assay 
Active assay: RNA (5245 features, 0 variable features)
[1] "674  cells are removed by these filters"

Platemap heatmap for failed cells

set up data

## make dataframe
df_platemap <- data.frame(well_name = pheno$well_name_R, cell_name = rownames(pheno), row.names = rownames(pheno))

## get cells that are filtered out
cells_kept <- which(rownames(df_platemap) %in% rownames(ss2_mutants_final@meta.data))

## make extra column in plotting df
df_platemap$colour <- "filtered_out"
df_platemap$colour[cells_kept] <- "passed_QC"

## inspect
head(df_platemap)

Make a table for each

table_platemap <- as.data.frame(table(df_platemap$well_name, df_platemap$colour))
names(table_platemap) <- c("well", "filtered", "frequency")

# make separate dfs
df_1 <- table_platemap[table_platemap$filtered == "filtered_out",]
df_2 <- table_platemap[table_platemap$filtered == "passed_QC",]

# merge them back together
table_platemap <- merge(df_1, df_2, by = "well", all = TRUE)

## remove the irrelevant rows and rename cols and rename rows
table_platemap <- table_platemap[ ,c(1,3,5)]
names(table_platemap) <- c("well", "filtered_out", "passed_QC")
table_platemap$well_name <- rownames(table_platemap)

## add cols for plotting
table_platemap$Row <- as.numeric(match(toupper(substr(table_platemap$well, 1, 1)), LETTERS))
table_platemap$Column <- as.numeric(substr(table_platemap$well, 2, 5))

## inspect:
head(table_platemap)
table_platemap$filtered_pc <- ((table_platemap$filtered_out)/(table_platemap$filtered_out + table_platemap$passed_QC))*100

## one way of manually colouring in points after
#+ scale_colour_manual(values=c(table_of_colors[1:2],c="green"))
## find wells where it's zero
zero_wells <- table_platemap$filtered_pc == 0
table_platemap$filtered_pc[zero_wells] <- NA

## plot
sample_map <- ggplot(data=table_platemap, aes(x=Column, y=Row)) +
  #set up the platemap layout
    geom_point(data=expand.grid(seq(1, 12), seq(1, 8)), aes(x=Var1, y=Var2), color="grey90", fill="white", shape=21, size=6) +
  #Change the shape and colour of points for a variable
  geom_point(aes(colour = filtered_pc)) +
  #change the colours
  scale_colour_viridis_c(guide = "colourbar", na.value="white") +
  #fix the ratio of coordinates
    coord_fixed(ratio=(13/12)/(9/8), xlim=c(0.5, 12.5), ylim=c(0.5, 8.5)) +
  #add labels for the y axis
    scale_y_reverse(breaks=seq(1, 8), labels=LETTERS[1:8]) +
  #add labels for the x axis
    scale_x_continuous(breaks=seq(1, 12)) +
  #Add a title
    labs(title="The position of cells that failed QC" , size = 6, colour = "percentage of cells in this well that failed QC") +
  #rotate legend guide because otherwise you can't see numbers:
    guides(fill = guide_colorbar(barwidth = 0.5, barheight = 10, title="Value")) +
  #change the colours
    #scale_color_manual(values=c("Hoechst"="blue", "Hoescht" = "blue", "mCherry"="red", "GFP"="green")) +
  # make mimnimum point size bigger
    #scale_size_continuous(range = c(2,10)) +
  # make into a plate plot
    theme_bdc_microtiter()

## print
sample_map

## save
ggsave("/Users/Andy/GCSKO/GCSKO_analysis_git/images_to_export/platemap_filtered.png", plot = sample_map, device = "png", path = NULL, scale = 1, width = 10, height = 10, units = "cm", dpi = 300, limitsize = TRUE)


## to make scatterpie
##library("scatterpie") # needed for geom_scatterpie
## then use this rather than geom_point and colour by
##+geom_scatterpie(aes(x=Column, y=Row, group = well), data=table_platemap, cols=c("filtered_out", "passed_QC"), color=NA, alpha=.8)

get a bar graph of this too

plot

Mapping Plot (Figure S6A)

prepare

plot

Recovery plots

How many cells are recovered per condition?

Investigate 20 and 2 further

add columns if it failed QC:

plot

Add bulk metadata

Add in bulk data predictions

hoo et al.

Kasia’s data

Can also do with Kasia’s timecourse data:

Normalisation

normalise and find variable genes

Dimensionality reduction

PCA

ss2_mutants_final <- RunPCA(ss2_mutants_final, features = VariableFeatures(object = ss2_mutants_final), verbose = FALSE)

PCA plot

DimPlot(ss2_mutants_final, reduction = "pca")
ElbowPlot(ss2_mutants_final, ndims = 30, reduction = "pca")

Find clusters

ss2_mutants_final <- FindNeighbors(ss2_mutants_final, dims = 1:21)
ss2_mutants_final <- FindClusters(ss2_mutants_final, resolution = 1)

UMAP

ss2_mutants_final <-RunUMAP(ss2_mutants_final, reduction = "pca", dims = 1:10, n.neighbors = 150, seed.use = 1234, min.dist = 0.4, repulsion.strength = 0.03, local.connectivity = 150)
DimPlot(ss2_mutants_final, reduction = "umap", group.by = "ident", label = TRUE, coord.fixed = TRUE)
#ss2_mutants_final <- RunUMAP(ss2_mutants_final, dims = 1:21)

UMAP Plots

#DimPlot(ss2_mutants_final, reduction = "umap", group.by = "ident", label = TRUE, coord.fixed = TRUE)
DimPlot(ss2_mutants_final, reduction = "umap", group.by = "identity_updated")

Cluster assignment

Interactive

plot <- FeaturePlot(ss2_mutants_final, features = "nFeature_RNA", reduction = "umap")   

HoverLocator(plot = plot, information = FetchData(ss2_mutants_final, vars = c("nFeature_RNA", "ident", "identity_updated")))

ngenes, nmito, ncounts visualisation

## add column to log counts so they are easier to visualise
ss2_mutants_final <- AddMetaData(ss2_mutants_final, log10(ss2_mutants_final@meta.data$nCount_RNA), col.name = "nCount_log10")

FeaturePlot(ss2_mutants_final, features = c("nCount_RNA", "nCount_log10", "nFeature_RNA", "percent.mt"), reduction = "umap")   

Violin plots cluster-by-cluster:

VlnPlot(object = ss2_mutants_final, features = "nFeature_RNA", pt.size = 0.01) +
  labs(x="Cluster",
       y="Genes per Cell",
       title = "Number of Genes per Cell") +
  theme(legend.position = "none")

VlnPlot(object = ss2_mutants_final, features = "nCount_log10", pt.size = 0.01) +
  labs(x="Cluster",
       y="Log10(Counts per Cell)",
       title = "Number of Counts per Cell") +
  theme(legend.position = "none")

VlnPlot(object = ss2_mutants_final, features = "percent.mt", pt.size = 0.01) +
  labs(x="Cluster",
       y="% Mitochondrial Reads",
       title = "Percentage of Mitochondrial Reads per Cell") +
  theme(legend.position = "none")

Expression of marker genes

# PBANKA-0515000 - p25 - female
# PBANKA-1319500 - CCP2 - female - used in 820 line
# PBANKA-1212600 - HAP2 - male
# PBANKA-0600600 - NEK3 - male
# PBANKA-1315700 - RON2 - (asexuals and some male?)
# "PBANKA-0416100" - dynenin heavy chain - male - used in 820 line
# PBANKA-1437500 - AP2-G - seuxal commitment gene
# PBANKA-0831000 - MSP1 - late asexual
# PBANKA-1102200 - MSP8 - early asexual (from Bozdech paper)
FeaturePlot(ss2_mutants_final, features = c("PBANKA-0515000", "PBANKA-1319500", "PBANKA-1212600","PBANKA-0600600", "PBANKA-1315700", "PBANKA-0416100", "PBANKA-1437500", "PBANKA-0831000", "PBANKA-1102200"), coord.fixed = TRUE)

Dotplot

df_meta_data <- as.data.frame(ss2_mutants_final@meta.data)

dot_plot_df <- as.data.frame.matrix(table(df_meta_data$RNA_snn_res.1, df_meta_data$identity_updated))

dot_plot_df_pc <- (as.data.frame.matrix(prop.table(table(df_meta_data$RNA_snn_res.1, df_meta_data$identity_updated), margin = 2)) * 100)

dot_plot_df_pc$cluster <- rownames(dot_plot_df_pc)
library(dplyr)
dot_plot_df_pc_mutated <- mutate(dot_plot_df_pc)
library(reshape2)
dot_plot_df_pc_melted <- melt(dot_plot_df_pc, variable.name = "cluster")
colnames(dot_plot_df_pc_melted)[2] <- "identity"
library(ggplot2)
  p = ggplot(dot_plot_df_pc_melted,
             aes(y = factor(cluster),
                 x = factor(identity))) +
      geom_point(aes(colour=value, size=value)) + 
      scale_color_gradient(low="blue", high="red", limits=c( 1, max(dot_plot_df_pc_melted$value)), na.value="white") +
      theme_bw() +
      theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank())
  p = p +
      ylab("Cluster") +
      xlab("Identity") +
      theme(axis.text.x=element_text(size=12, face="italic", angle=45, hjust=1)) + 
      theme(axis.text.y=element_text(size=12, face="italic"))
  print(p)

expression of 820 markers

plots <- FeaturePlot(ss2_mutants_final, features = c("PBANKA-1319500", "PBANKA-0416100"), blend = TRUE, combine = FALSE, coord.fixed = TRUE)

plots[[3]] + NoLegend()  # Get just the co-expression plot, built-in legend is meaningless for this plot
plots[[4]] # Get just the key
CombinePlots(plots[3:4], legend = 'none') # Stitch the co-expression and key plots together

identify which cluster is which

# PBANKA-1319500 - CCP2 - female - used in 820 line
# PBANKA-0416100 - dynenin heavy chain - male - used in 820 line
# PBANKA-0831000 - MSP1 - late asexual
# PBANKA-1102200 - MSP8 - early asexual (from Bozdech paper)
DotPlot(ss2_mutants_final, features = c("PBANKA-1319500", "PBANKA-0416100", "PBANKA-0831000", "PBANKA-1102200"))

# 18 - asex early - 1
# 17 - female
# 16 - female
# 15 - male
# 14 - female (with some late asex?)
# 13 - male
# 12 - asex early - 3
# 11 - male
# 10 - asex early - 0
# 9 - DEV branch
# 8 - asex late - 0
# 7 - female
# 6 - asex late - 1
# 5 - asex late - 2
# 4 - DEV branch
# 3 - asex early - 2
# 2 - asex late - 3
# 1 - male
# 0 - female
## change the levels in the meta data
ss2_mutants_final@meta.data$seurat_clusters_plotting <- ss2_mutants_final@meta.data$seurat_clusters

## reorder the levels so you can plot the cluters as you wish

# Define order of appearance of timepoints
my_levels <- c("0", "6", "12", "14", "16", "1", "10", "13", "15","3", "8","7", "5", "2", "9", "17", "4", "11")

# Relevel object@timepoint
ss2_mutants_final@meta.data$seurat_clusters_plotting <- factor(x = ss2_mutants_final@meta.data$seurat_clusters_plotting, levels = my_levels)

DotPlot(ss2_mutants_final, features = c("PBANKA-1319500", "PBANKA-0416100", "PBANKA-0831000", "PBANKA-1102200"), group.by = "seurat_clusters_plotting") + theme(axis.text.x = element_text(angle = 90))

Confirm life cycle designations:

FeaturePlot(ss2_mutants_final, features = c("Prediction(Spearman)_Kasia", "Prediction(Spearman)"))

During check, just ran to here

Improve UMAP

ss2_mutants_final <- RunUMAP(ss2_mutants_final, dims = 1:12, reduction.name = "umap_improved")
DimPlot(ss2_mutants_final, reduction = "umap_improved", group.by = "ident", label = TRUE, coord.fixed = TRUE)

4. Cluster together with MCA data

Prepare

set up MCA data

## read in data
counts_mca <- read.table("MCA/allcounts4.csv", header = TRUE, sep = ",", row.names=1, stringsAsFactors = TRUE)
dim(counts_mca)

anno_mca <- read.delim("MCA/allpheno8.2.csv", header = TRUE, sep = ",", row.names=1)
dim(anno_mca)

## subset all blood stage cells
## find blood stages
blood_stages <- c("Merozoite", "Shz", "Male", "Schizont", "Female", "Trophozoite", "Ring")

blood_stage_cell_names <- rownames(anno_mca[anno_mca$ShortenedLifeStage2 %in% blood_stages, ])

## subset dataframes
counts_mca_blood_stage <- counts_mca[ ,colnames(counts_mca) %in% blood_stage_cell_names]
dim(counts_mca_blood_stage)

anno_mca_blood_stage <- anno_mca[rownames(anno_mca) %in% blood_stage_cell_names, ]
dim(anno_mca_blood_stage)

## remove control cells:
non_control_cell_names <- rownames(anno_mca_blood_stage[anno_mca_blood_stage$Number_of_cells == 1, ])
counts_mca_blood_stage <- counts_mca_blood_stage[ ,colnames(counts_mca_blood_stage) %in% non_control_cell_names]
dim(counts_mca_blood_stage)

anno_mca_blood_stage <- anno_mca_blood_stage[rownames(anno_mca_blood_stage) %in% non_control_cell_names, ]
dim(anno_mca_blood_stage)

## check
identical(rownames(counts_mca_blood_stage), rownames(counts))

set up MCA object

mca object

## make Seurat object with same filtering as main object because they are sequenced to same depth:
GCSKO_mca <- CreateSeuratObject(counts = counts_mca_blood_stage, meta.data = anno_mca_blood_stage, min.cells = 0, min.features = 120, project = "GCSKO")

GCSKO_mca

GCSKO_mca@meta.data$experiment <- "mca"
ss2_mutants_final@meta.data$experiment <- "ss2_mutants"

n.b. a filter of 40 allows the merozoites to complete the ring in the asexuals

VlnPlot(object = GCSKO_mca, features = "nFeature_RNA", pt.size = 0.01) +
  labs(x="Cluster",
       y="Genes per Cell",
       title = "Number of Genes per Cell") +
  theme(legend.position = "none") + geom_hline(yintercept=220)

VlnPlot(object = GCSKO_mca, features = "nCount_RNA", pt.size = 0.01) +
  labs(x="Cluster",
       y="Log10(Counts per Cell)",
       title = "Number of Counts per Cell") +
  theme(legend.position = "none")

normalise object

## normalise
GCSKO_mca <- NormalizeData(GCSKO_mca, normalization.method = "LogNormalize", scale.factor = 10000)
## find variable genes
GCSKO_mca <- FindVariableFeatures(GCSKO_mca, selection.method = "vst", nfeatures = 2000)
## make a list of all genes in the dataset
all.genes <- rownames(GCSKO_mca)
## scale data on all genes
GCSKO_mca <- ScaleData(GCSKO_mca, features = all.genes)

Integrate

## make list
ss2.mca.list <- list(GCSKO_mca, ss2_mutants_final)
ss2.mca.anchors <- FindIntegrationAnchors(object.list = ss2.mca.list, dims = 1:21, verbose = FALSE)
ss2.mca.integrated <- IntegrateData(anchorset = ss2.mca.anchors, dims = 1:21, verbose = FALSE, features.to.integrate = all.genes)

Analyse

Scale and PCA

# set during IntegrateData
DefaultAssay(ss2.mca.integrated) <- "integrated"
# Run the standard workflow for visualization and clustering
ss2.mca.integrated <- ScaleData(ss2.mca.integrated, verbose = FALSE)
ss2.mca.integrated <- RunPCA(ss2.mca.integrated, npcs = 30, verbose = FALSE)

Inspect PCS:

ElbowPlot(ss2.mca.integrated, ndims = 30, reduction = "pca")

UMAP

ss2.mca.integrated <- RunUMAP(ss2.mca.integrated, reduction = "pca", dims = 1:21)

UMAP plot:

#names(tenx.mca.integrated@meta.data)[9] <- "Prediction_Spearman"
p1 <- DimPlot(ss2.mca.integrated, reduction = "umap", group.by = "experiment", pt.size = 0.01) + coord_fixed()
p2 <- DimPlot(ss2.mca.integrated, reduction = "umap", group.by = "ShortenedLifeStage2", label = TRUE, repel = TRUE, pt.size = 0.01) + coord_fixed()
p3 <- DimPlot(ss2.mca.integrated, reduction = "umap", group.by = "RNA_snn_res.1", label = TRUE, repel = TRUE, pt.size = 0.01) + coord_fixed()
p1 + p2
p3

UMAP optimisation

try to make a better UMAP:

for(i in c(20,200,400,800,1200)){
ss2.mca.integrated <- RunUMAP(ss2.mca.integrated, reduction = "pca", dims = 1:21, seed.use = i)

assign(paste0("UMAP_", i) ,DimPlot(ss2.mca.integrated, reduction = "umap", group.by = "RNA_snn_res.1", label = TRUE, repel = TRUE, pt.size = 0.01) + coord_fixed())
}
UMAP_20
UMAP_200
UMAP_400
UMAP_800
UMAP_1200
#ss2.mca.integrated <- RunUMAP(ss2.mca.integrated, reduction = "pca", dims = 1:21, seed.use = 800)
ss2.mca.integrated <- RunUMAP(ss2.mca.integrated, reduction = "pca", dims = 1:15)
DimPlot(ss2.mca.integrated, reduction = "umap", group.by = "RNA_snn_res.1", label = TRUE, repel = TRUE, pt.size = 0.01) + coord_fixed()
VlnPlot(object = ss2.mca.integrated, features = "nFeature_RNA", pt.size = 0.01) + geom_hline(yintercept=100)

plot:

p1 <- DimPlot(ss2.mca.integrated, pt.size = 0.01, label = TRUE)
p2 <- DimPlot(ss2.mca.integrated, pt.size = 0.01, group.by = "ShortenedLifeStage2", label = TRUE)
p1 + p2
## add new column 
ss2.mca.integrated@meta.data$clusters_integrated <- ss2.mca.integrated@meta.data$seurat_clusters

ss2.mca.integrated@meta.data$clusters_integrated <- ifelse(is.na(ss2.mca.integrated@meta.data$clusters_integrated), ss2.mca.integrated@meta.data$ShortenedLifeStage2, ss2.mca.integrated@meta.data$clusters_integrated)

DimPlot(ss2.mca.integrated, pt.size = 0.01, label = TRUE, split.by = "experiment", group.by = "clusters_integrated") + coord_fixed() + theme_void()
plots <- FeaturePlot(ss2.mca.integrated, features = c("PBANKA-1319500", "PBANKA-0416100"), blend = TRUE, combine = FALSE, coord.fixed = TRUE, split.by = "experiment")

plots[[7]] + NoLegend()  # Get just the co-expression plot, built-in legend is meaningless for this plot
plots[[8]] # Get just the key
CombinePlots(plots[3:4], legend = 'none', ncol =2, nrow = 1, rel_widths = c(2, 1), rel_heights = c(4,1)) # Stitch the co-expression and key plots together

cluster

generate clusters:

## copy old clusters
ss2.mca.integrated <- AddMetaData(ss2.mca.integrated, ss2.mca.integrated@meta.data$RNA_snn_res.1, col.name = "pre_integration_clusters")

## generate new clusters
#ss2.mca.integrated <- FindNeighbors(ss2.mca.integrated, dims = 1:21)
#ss2.mca.integrated <- FindClusters(ss2.mca.integrated, resolution = 1, random.seed = 42, algorithm = 2)

Sex ratio plots

Calculate sex ratios

## this will only subset SS2 cells as these are the only ones with identities

## subset males
ss2_mutants_final_male <- SubsetData(ss2_mutants_final, ident.use = c(1,10,13,16))

## subset females
ss2_mutants_final_female <- SubsetData(ss2_mutants_final, ident.use = c(0,9,11,14,15,5))

## inspect
ss2_mutants_final_male
ss2_mutants_final_female
## calculate sex ratios
##subset out H+ sorted cells:
df_male <- ss2_mutants_final_male@meta.data[ss2_mutants_final_male@meta.data$exclude_for_sex_ratio == FALSE,]

dim(df_male)

df_female <- ss2_mutants_final_female@meta.data[ss2_mutants_final_female@meta.data$exclude_for_sex_ratio == FALSE,]

dim(df_female)

## make dataframe
df_sex_ratio <- merge(
  as.data.frame(table(df_male$sub_identity_updated)), 
  as.data.frame(table(df_female$sub_identity_updated)), 
  by = "Var1", all=TRUE)

# or use identity_updated

## add names
names(df_sex_ratio) <- c("genotype", "male", "female")

## change the NAs to 0
df_sex_ratio[is.na(df_sex_ratio)] <- 0

## calculate sex ratio
df_sex_ratio$sex_ratio <- (df_sex_ratio$male + 1)/(df_sex_ratio$female)

## log sex ratio
df_sex_ratio$sex_ratio_log <- log10(df_sex_ratio$sex_ratio)

##view
df_sex_ratio

plot

## reorder genotype so it is in the correct order for plotting
#df_sex_ratio$genotype <- factor(df_sex_ratio$genotype, levels = c("GCSKO-2", "GCSKO-3", "WT-3", "GCSKO-10_820", "GCSKO-13", "WT-13", "GCSKO-17", "WT-17", "GCSKO-19", "WT-19", "GCSKO-20", "WT-20", "GCSKO-glasgow", "GCSKO-28", "GCSKO-29", "GCSKO-oom", "WT-820"))

## make extra column for plotting aesthetics:
df_sex_ratio$above <- df_sex_ratio$sex_ratio_log > 1

## plot
ggplot(df_sex_ratio, aes(sex_ratio_log, reorder(genotype, sex_ratio_log, sum), color = above)) +
      geom_segment(aes(x = 1, y = genotype, xend = sex_ratio_log, yend = genotype), color = "grey50") +
      geom_point() +
      annotate("rect", xmin= -0.30103000, xmax = 1.02118930, ymin=-Inf , ymax=Inf, alpha=0.1, color=NA,linetype = 2, fill="blue") +
        theme_classic()
  
## https://uc-r.github.io/lollipop

Save

save counts and pheno without anopheles and control cells

write.csv(counts, file = "~/data_to_export/counts_2020_filtered.csv")
write.csv(pheno, file = "~/data_to_export/pheno_2020_filtered.csv")
pheno_filtered_cells <- ss2_mutants_final@meta.data
counts_filtered_cells <- ss2_mutants_final@assays$RNA@counts

write.csv(counts_filtered_cells, file = "~/data_to_export/counts_filtered_cells.csv")
write.csv(pheno_filtered_cells, file = "~/data_to_export/pheno_filtered_cells.csv")

save the session objects

save.image(file = "~/GCSKO_SS2_QC.RData")
#load(file = "~/GCSKO_SS2_QC.RData")

save.image(file = "~/GCSKO_SS2_QC.RData")
#load(file = "~/GCSKO_SS2_QC.RData")

saveRDS(ss2_mutants_final, file = "ss2_mutants_final.RDS") 
#ss2_mutants_final <- readRDS("ss2_mutants_final.RDS")

Appendix

Session Info

Extras

testing Vikash’s cells

vikash_filtered_cells <- read.table("~/data/vikash_filtered_cells_20_03_27.txt", sep="\t", header = TRUE)
head(vikash_filtered_cells)
vikash_keep_cells <- vikash_filtered_cells[vikash_filtered_cells$final_call == 1,]$X

table(vikash_filtered_cells$final_call)

ss2_mutants_final

table(rownames(ss2_mutants_final@meta.data) %in% vikash_keep_cells)

QC plot with these metrics:

## make dataframe of just metrics
counts_metrics <- counts_genes[-(grep("PBANKA*", rownames(counts_genes))), ]

## inspect
counts_metrics[1:5,1:5]

## transpose dataframe
counts_metrics_plot <- as.data.frame(t(counts_metrics))

## inspect
counts_metrics_plot[1:5,1:5]

prepare the dataframe for plotting:

## make a column for name of cell
counts_metrics_plot$cell_name <- rownames(counts_metrics_plot)
## order by column
#counts_metrics_plot <- counts_metrics_plot[order(counts_metrics_plot$`__not_aligned`, decreasing=T),]
## melt
counts_metrics_plot <- melt(counts_metrics_plot, id.vars = "cell_name")
## count number of zero values:
length(which(counts_metrics_plot$value == 0))
## log the value
counts_metrics_plot$value <- log(counts_metrics_plot$value + 1, 10)
#meltR$experiment <- factor(meltR$experiment, levels = meltR$experiment[order(-meltR$value[meltR$variable == lev])])
## reorder based on one metric (namely not mapped here)
counts_metrics_plot$cell_name <- factor(counts_metrics_plot$cell_name, levels = counts_metrics_plot$cell_name[order(-counts_metrics_plot$value[counts_metrics_plot$variable == levels(counts_metrics_plot$variable)[4]])])
    
## to reorder just based on sum:
#ggplot(counts_metrics_plot, aes(fill=variable, y=value, x=reorder(cell_name, value, sum))) + 
#    geom_bar(position="stack", stat="identity")

## ref: https://stackoverflow.com/questions/40020386/reorder-according-variable-of-melted-dataframe 
## plot
ggplot(counts_metrics_plot, aes(fill=variable, y=value, x=cell_name)) + 
  geom_bar(position="stack", stat="identity") +
  # label plot
  labs(x = "Cells", y = "log10(number of reads)") +
  # remove the x axis
  theme(axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.line.x = element_blank())

plot with mapped statistics:

## make a dataframe of all mapped reads
mapped_reads <- as.data.frame(colSums(counts))
## transpose the metrics for merging
counts_metrics_full <- as.data.frame(t(counts_metrics))
## check that the rownames are identical
#identical(rownames(counts_metrics_full), rownames(mapped_reads))
## bind the dataframes together
counts_metrics_full <- cbind(counts_metrics_full, mapped_reads)
## make a column for cell name
counts_metrics_full$cell_name <- rownames(counts_metrics_full)
## melt
counts_metrics_full <- melt(counts_metrics_full, id.vars = "cell_name")
## count number of zero values:
length(which(counts_metrics_full$value == 0))
## log the value
counts_metrics_full$value <- log(counts_metrics_full$value + 1, 10)

plot:

## plot
ggplot(counts_metrics_full, aes(fill=variable, y=value, x=reorder(cell_name, value, sum))) + 
  geom_bar(position="stack", stat="identity") +
  # label plot
  labs(x = "Cells", y = "log10(number of reads)") +
  # remove the x axis
  theme(axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.line.x = element_blank())

3. Analysis

Light filter

ss2_mutants_filtered <- subset(ss2_mutants, subset = nFeature_RNA > 40 & nFeature_RNA < 5246 & percent.mt < 101 & nCount_RNA > 1000)
ss2_mutants_filtered

4358 - 3640 = 718 cells were removed by this very light filter

filter genes

## how many genes are not detected at all now that it is filtered of bad cells?
length(which(rowSums(ss2_mutants_filtered@assays$RNA@counts) == 0))

Filtered Object

normalise and find variable genes

## normalise
ss2_mutants_filtered <- NormalizeData(ss2_mutants_filtered, normalization.method = "LogNormalize", scale.factor = 10000)
## find variable genes
ss2_mutants_filtered <- FindVariableFeatures(ss2_mutants_filtered, selection.method = "vst", nfeatures = 2000)
## make a list of all genes in the dataset
all.genes <- rownames(ss2_mutants_filtered)
## scale data on all genes
ss2_mutants_filtered <- ScaleData(ss2_mutants_filtered, features = all.genes)

plot

ss2_mutants_filtered <- RunPCA(ss2_mutants_filtered, features = VariableFeatures(object = ss2_mutants_filtered))
DimPlot(ss2_mutants_filtered, reduction = "pca")
ElbowPlot(ss2_mutants_filtered, ndims = 30, reduction = "pca")
ss2_mutants_filtered <- FindNeighbors(ss2_mutants_filtered, dims = 1:21)
ss2_mutants_filtered <- FindClusters(ss2_mutants_filtered, resolution = 1)
ss2_mutants_filtered <- RunUMAP(ss2_mutants_filtered, dims = 1:21)
DimPlot(ss2_mutants_filtered, reduction = "umap", group.by = "ident", label = TRUE)
DimPlot(ss2_mutants_filtered, reduction = "umap", group.by = "identity_updated")
ss2_mutants_filtered <- AddMetaData(ss2_mutants_filtered, log10(ss2_mutants_filtered@meta.data$nCount_RNA), col.name = "nCount_log10")

FeaturePlot(ss2_mutants_filtered, features = c("nCount_RNA", "nCount_log10", "nFeature_RNA", "percent.mt"), reduction = "umap")   

interactive

plot <- FeaturePlot(ss2_mutants_filtered, features = "nFeature_RNA", reduction = "umap")   

HoverLocator(plot = plot, information = FetchData(ss2_mutants_filtered, vars = c("nFeature_RNA", "ident", "identity_updated")))

look at this on a cluster-by-cluster basis:

VlnPlot(object = ss2_mutants_filtered, features = "nFeature_RNA", pt.size = 0.01) + geom_hline(yintercept=250)
VlnPlot(object = ss2_mutants_filtered, features = "nCount_log10", pt.size = 0.01)
VlnPlot(object = ss2_mutants_filtered, features = "percent.mt", pt.size = 0.01) + geom_hline(yintercept=20)
cluster_four_cells_df <- ss2_mutants_filtered@meta.data[(ss2_mutants_filtered@meta.data$seurat_clusters == 4),]

ggplot(cluster_four_cells_df, aes(x = percent.mt, y = nFeature_RNA)) + geom_point(size = 1)

#FeatureScatter(ss2_mutants_filtered, feature1 = "percent.mt", feature2 = "nFeature_RNA", cells = , pt.size = 0.01, group.by = "experiment")

idenitfy which clusters are which

# PBANKA-0515000 - p25 - female
# PBANKA-1319500 - CCP2 - female - used in 820 line
# PBANKA-1212600 - HAP2 - male
# PBANKA-0600600 - NEK3 - male
# PBANKA-1315700 - RON2 - (asexuals and some male?)
# PBANKA-0416100 - dynenin heavy chain - male - used in 820 line
# PBANKA-1437500 - AP2-G - seuxal commitment gene
# PBANKA-0831000 - MSP1 - late asexual
# PBANKA-1102200 - MSP8 - early asexual (from Bozdech paper)
FeaturePlot(ss2_mutants_filtered, features = c("PBANKA-0515000", "PBANKA-1319500", "PBANKA-1212600","PBANKA-0600600", "PBANKA-1315700", "PBANKA-0416100", "PBANKA-1437500", "PBANKA-0831000", "PBANKA-1102200"), coord.fixed = TRUE)

prep for dotplot

df_meta_data <- as.data.frame(ss2_mutants_filtered@meta.data)

dot_plot_df <- as.data.frame.matrix(table(df_meta_data$RNA_snn_res.1, df_meta_data$identity_updated))

dot_plot_df_pc <- (as.data.frame.matrix(prop.table(table(df_meta_data$RNA_snn_res.1, df_meta_data$identity_updated), margin = 2)) * 100)

dot_plot_df_pc$cluster <- rownames(dot_plot_df_pc)
library(dplyr)
dot_plot_df_pc_mutated <- mutate(dot_plot_df_pc)
library(reshape2)
dot_plot_df_pc_melted <- melt(dot_plot_df_pc, variable.name = "cluster")
colnames(dot_plot_df_pc_melted)[2] <- "identity"
library(ggplot2)
  p = ggplot(dot_plot_df_pc_melted,
             aes(y = factor(cluster),
                 x = factor(identity))) +
      geom_point(aes(colour=value, size=value)) + 
      scale_color_gradient(low="blue", high="red", limits=c( 1, max(dot_plot_df_pc_melted$value))) +
      theme_bw() +
      theme(panel.grid.major=element_blank(), panel.grid.minor=element_blank())
  p = p +
      ylab("Cluster") +
      xlab("Identity") +
      theme(axis.text.x=element_text(size=12, face="italic", angle=45, hjust=1)) + 
      theme(axis.text.y=element_text(size=12, face="italic"))
  print(p)

Old way of plotting microtitre plates

The previous way of plotting plates broke.

The packages involved are: ggplot2 3.2.1 (web instance) vs 3.3.2 (here) ggplot2bdc 0.3.2 (web instance) vs. 0.3.2 (here)

Something happened in the ggplot2 update that meant the title and guides were superimposed on the plot. The specific issue was with the scale_y_reverse() function.

sample_map <- ggplot(data=table_platemap, aes(x=Column, y=Row)) +
  #set up the platemap layout
    geom_point(data=expand.grid(seq(1, 12), seq(1, 8)), aes(x=Var1, y=Var2), color="grey90", fill="white", shape=21, size=6) +
  #Change the shape and colour of points for a variable
  geom_point(aes(colour = filtered_pc)) +
  #change the colours
  scale_colour_viridis_c(guide = "colourbar", na.value="white") +
  #fix the ratio of coordinates
    coord_fixed(ratio=(13/12)/(9/8), xlim=c(0.5, 12.5), ylim=c(0.5, 8.5)) +
  #add labels for the y axis
    scale_y_reverse(breaks=seq(1, 8), labels=LETTERS[1:8]) +
  #add labels for the x axis
    scale_x_continuous(breaks=seq(1, 12)) +
  #Add a title
    labs(title="The position of cells that failed QC" , size = 6, colour = "percentage of cells in this well that failed QC") +
  #rotate legend guide because otherwise you can't see numbers:
    guides(fill = guide_colorbar(barwidth = 0.5, barheight = 10, title="Value")) +
  #change the colours
    #scale_color_manual(values=c("Hoechst"="blue", "Hoescht" = "blue", "mCherry"="red", "GFP"="green")) +
  # make mimnimum point size bigger
    #scale_size_continuous(range = c(2,10)) +
  # make into a plate plot
    theme_bdc_microtiter()

sample_map
LS0tCnN1YnRpdGxlOiAnR2FtZXRvY3l0ZSBEZXZlbG9wbWVudCBpbiA8aT5QbGFzbW9kaXVtIGJlcmdoZWk8L2k+Jwp0aXRsZTogfAogICFbXSgvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvR0NTS09fbG9nby5qcGcpe3dpZHRoPTMwMHB4fSAgCiAgU21hcnQtc2VxMiBRdWFsaXR5IENvbnRyb2wKYXV0aG9yOiAiW0FuZHJldyBSdXNzZWxsXShodHRwczovL2FqY3J1c3NlbGwud2l4c2l0ZS5jb20vbXlzaXRlL2Fib3V0KSIKaW5zdGl0dXRlOiBXZWxsY29tZSBTYW5nZXIgSW5zdGl0dXRlCmRhdGU6ICdgciBmb3JtYXQoU3lzLkRhdGUoKSwgIiVCICVkLCAlWSIpYCcKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0aGVtZTogY29zbW8KICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDMKICAgICN0b2NfZmxvYXQ6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKKioqCiMgMS4gUmVhZCBpbiB0aGUgZGF0YSAgey50YWJzZXR9CgojIyMgTG9hZCB0aGUgcmVxdWlyZWQgcGFja2FnZXMKCmBgYHtyLCBlY2hvID0gRkFMU0V9CgojIyBTZXVyYXQgaXMgbmVlZGVkIGZvciBtb3N0IG9mIHRoaXMgc2NyaXB0CmlmKHJlcXVpcmUoIlNldXJhdCIsIHF1aWV0bHkgPSBUUlVFKSl7CiAgICBwcmludCgiU2V1cmF0IGlzIGxvYWRlZCBjb3JyZWN0bHkiKQp9IGVsc2UgewogICAgcHJpbnQoInRyeWluZyB0byBpbnN0YWxsIFNldXJhdCIpCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJTZXVyYXQiKQogICAgaWYocmVxdWlyZShTZXVyYXQpKXsKICAgICAgICBwcmludCgiU2V1cmF0IGluc3RhbGxlZCBhbmQgbG9hZGVkIikKICAgIH0gZWxzZSB7CiAgICAgICAgc3RvcCgiY291bGQgbm90IGluc3RhbGwgU2V1cmF0IikKICAgIH0KfQoKIyMgdmlyaWRpcyBpcyBuZWVkZWQgdG8gY29sb3VyIGRhdGEgaW4gcGxvdHMKaWYocmVxdWlyZSgidmlyaWRpcyIsIHF1aWV0bHkgPSBUUlVFKSl7CiAgICBwcmludCgidmlyaWRpcyBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCB2aXJpZGlzIikKICAgIGluc3RhbGwucGFja2FnZXMoInZpcmlkaXMiKQogICAgaWYocmVxdWlyZSh2aXJpZGlzKSl7CiAgICAgICAgcHJpbnQoInZpcmlkaXMgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCB2aXJpZGlzIikKICAgIH0KfQoKIyMgZ2dwdWJyIGlzIG5lZWRlZCBmb3IgcGxvdHRpbmcKaWYocmVxdWlyZSgiZ2dwdWJyIiwgcXVpZXRseSA9IFRSVUUpKXsKICAgIHByaW50KCJnZ3B1YnIgaXMgbG9hZGVkIGNvcnJlY3RseSIpCn0gZWxzZSB7CiAgICBwcmludCgidHJ5aW5nIHRvIGluc3RhbGwgZ2dwdWJyIikKICAgIGluc3RhbGwucGFja2FnZXMoImdncHViciIpCiAgICBpZihyZXF1aXJlKGdncHVicikpewogICAgICAgIHByaW50KCJnZ3B1YnIgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBnZ3B1YnIiKQogICAgfQp9CgojIyBjb3dwbG90IGlzIG5lZWRlZCBmb3IgcGxvdHRpbmcKaWYocmVxdWlyZSgiY293cGxvdCIsIHF1aWV0bHkgPSBUUlVFKSl7CiAgICBwcmludCgiY293cGxvdCBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBjb3dwbG90IikKICAgIGluc3RhbGwucGFja2FnZXMoImNvd3Bsb3QiKQogICAgaWYocmVxdWlyZShjb3dwbG90KSl7CiAgICAgICAgcHJpbnQoImNvd3Bsb3QgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBjb3dwbG90IikKICAgIH0KfQoKIyMgZ2dwbG90MmJkYyBpcyBuZWVkZWQgZm9yIHBsb3R0aW5nIHBsYXRlIG1hcHMKaWYocmVxdWlyZSgiZ2dwbG90MmJkYyIsIHF1aWV0bHkgPSBUUlVFKSl7CiAgICBwcmludCgiZ2dwbG90MmJkYyBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBnZ3Bsb3QyYmRjIikKICAgIGlmKCFyZXF1aXJlKCJkZXZ0b29scyIpKSBpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpCiAgICBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImJyaWFuZGNvbm5lbGx5L2dncGxvdDJiZGMiKQogICAgaWYocmVxdWlyZShnZ3Bsb3QyYmRjKSl7CiAgICAgICAgcHJpbnQoImdncGxvdDJiZGMgaW5zdGFsbGVkIGFuZCBsb2FkZWQiKQogICAgfSBlbHNlIHsKICAgICAgICBzdG9wKCJjb3VsZCBub3QgaW5zdGFsbCBnZ3Bsb3QyYmRjIikKICAgIH0KfQoKIyMgcGF0Y2h3b3JrIGlzIG5lZWRlZCBmb3IgcGxvdHRpbmcKIyMgV0FSTklORyEgY293cGxvdCBvdmVyLXJpZGVzIHRoaXMgYnkgbWFza2luZyBpdCBzbyBiZSBjYXJlZnVsLgppZihyZXF1aXJlKCJwYXRjaHdvcmsiLCBxdWlldGx5ID0gVFJVRSkpewogICAgcHJpbnQoInBhdGNod29yayBpcyBsb2FkZWQgY29ycmVjdGx5IikKfSBlbHNlIHsKICAgIHByaW50KCJ0cnlpbmcgdG8gaW5zdGFsbCBwYXRjaHdvcmsiKQogICAgaW5zdGFsbC5wYWNrYWdlcygicGF0Y2h3b3JrIikKICAgIGlmKHJlcXVpcmUocGF0Y2h3b3JrKSl7CiAgICAgICAgcHJpbnQoInBhdGNod29yayBpbnN0YWxsZWQgYW5kIGxvYWRlZCIpCiAgICB9IGVsc2UgewogICAgICAgIHN0b3AoImNvdWxkIG5vdCBpbnN0YWxsIHBhdGNod29yayIpCiAgICB9Cn0KYGBgCgojIyMgSW1wb3J0IEdURiBmaWxlCgpUaGlzIHdpbGwgYmUgaGVscGZ1bCBsYXRlciBvbi4gVGhpcyBjb250YWlucyBhbm5vdGF0aW9ucyBmb3IgZWFjaCBnZW5lOgpgYGB7cn0KIyNJbXBvcnQgZ3RmIGZpbGU6Cmd0ZiA8LSByZWFkLnRhYmxlKCIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvZGF0YS9QYmVyZ2hlaS5ndGYiLCBzZXA9Ilx0IiwgaGVhZGVyID0gRkFMU0UpCmhlYWQoZ3RmKQpgYGAKKk4uQi5UaGlzIHdhcyB0aGUgLmd0ZiBmaWxlIHVzZWQgZm9yIGZlYXR1cmUgY291bnRpbmcgdGhlIGRhdGEKCiMjIyBJbXBvcnQgQ291bnRzIGFuZCBQaGVubyBmaWxlcwpgYGB7cn0KIyMgcmVhZCBpbiBjb3VudHMKY291bnRzIDwtIHJlYWQuZGVsaW0oIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9kYXRhL2NvdW50c18yMDIwLmNzdiIsIHNlcCA9ICIsIiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFLCByb3cubmFtZXMgPSAxKQoKIyMgcmVhZCBpbiBwaGVubwpwaGVubyA8LSByZWFkLmRlbGltKCIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvZGF0YS9waGVub18yMDIwLmNzdiIsIHNlcCA9ICIsIiwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKIyMgY2hlY2sgZGltZW5zaW9ucyBvZiBib3RoCmV4cGVjdGVkX251bWJlcl9vZl9jZWxscyA8LSAoIDM4NCAqIDEyKQpwYXN0ZSgiVGhlIGV4cGVjdGVkIG51bWJlciBvZiBjZWxscyBpcyIsIGV4cGVjdGVkX251bWJlcl9vZl9jZWxscykKcGFzdGUoIm51bWJlciBvZiBnZW5lcyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsxXSwgIm51bWJlciBvZiBjZWxscyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsyXSkKcGFzdGUoIm51bWJlciBvZiBjb2x1bW5zIGluIGNvdW50cyIsIGRpbShwaGVubylbMl0sICJudW1iZXIgb2YgY2VsbHMgaW4gcGhlbm8iLCBkaW0ocGhlbm8pWzFdKQoKIyMgbWFrZSByb3duYW1lcyB0aGUgc2FtcGxlX2lkIGluIHBoZW5vCnJvd25hbWVzKHBoZW5vKSA8LSBwaGVubyRzYW1wbGVfaWQKCiMjIGNoZWNrIHRoYXQgdGhlIG5hbWVzIGFyZSB0aGUgc2FtZQpwYXN0ZSgiQXJlIHRoZSBuYW1lcyB0aGUgc2FtZT8iKQp0YWJsZSgoY29sbmFtZXMoY291bnRzKSAlaW4lIHJvd25hbWVzKHBoZW5vKSkpCmBgYAoKIyMjIFJlbW92ZSBBbm9waGVsZXMgY2VsbHMKClRoZXNlIGNlbGxzIHdlcmUgaW5jbHVkZWQgaW4gb25lIG9mIHRoZSBzZXF1ZW5jaW5nIHJ1bnMgYW5kIGFyZSBpcnJlbGV2YW50LgpgYGB7cn0KIyMgZ2V0IHJpZCBvZiB0aGUgY2VsbHMgYnkgZmluZGluZyBhbGwgdGhlIGNlbGxzIHRoYXQgaGF2ZSBBcyBpbiB0aGVpciBzcGVjaWVzIGNvbApuYW1lc19vZl9tb3NxdWl0b19jZWxscyA8LSByb3duYW1lcyhwaGVub1socGhlbm8kc3BlY2llcyA9PSAiQXMiKSwgXSkKCiMjIHdoaWNoIGdpdmVzCnRhYmxlKGNvbG5hbWVzKGNvdW50cykgJWluJSBuYW1lc19vZl9tb3NxdWl0b19jZWxscykKCiMjIHN1YnNldCAKY291bnRzIDwtIGNvdW50c1ssLXdoaWNoKGNvbG5hbWVzKGNvdW50cykgJWluJSBuYW1lc19vZl9tb3NxdWl0b19jZWxscyldCnBoZW5vIDwtIHBoZW5vWy0od2hpY2gocm93bmFtZXMocGhlbm8pICVpbiUgbmFtZXNfb2ZfbW9zcXVpdG9fY2VsbHMpKSwgXQoKIyMgY2hlY2sgZGltZW5zaW9ucwpwYXN0ZSgibnVtYmVyIG9mIGdlbmVzIGluIGNvdW50cyIsIGRpbShjb3VudHMpWzFdLCAibnVtYmVyIG9mIGNlbGxzIGluIGNvdW50cyIsIGRpbShjb3VudHMpWzJdKQpwYXN0ZSgibnVtYmVyIG9mIGNvbHVtbnMgaW4gY291bnRzIiwgZGltKHBoZW5vKVsyXSwgIm51bWJlciBvZiBjZWxscyBpbiBwaGVubyIsIGRpbShwaGVubylbMV0pCmBgYAoKIyMjIFJlbW92ZSBjb250cm9sIGNlbGxzOgpgYGB7cn0KIyMgZmluZCBhbGwgY2VsbHMgdGhhdCBhcmUgbGFiZWxsZWQgYXMgc3VjaApuYW1lc19vZl9jb250cm9sX2NlbGxzIDwtIHJvd25hbWVzKHBoZW5vWyhwaGVubyRpc19jb250cm9sID09ICJUUlVFIiksIF0pCgojIyB3aGljaCBnaXZlcwp0YWJsZShjb2xuYW1lcyhjb3VudHMpICVpbiUgbmFtZXNfb2ZfY29udHJvbF9jZWxscykKCiMjIHN1YnNldCAKY291bnRzIDwtIGNvdW50c1ssLXdoaWNoKGNvbG5hbWVzKGNvdW50cykgJWluJSBuYW1lc19vZl9jb250cm9sX2NlbGxzKV0KcGhlbm8gPC0gcGhlbm9bLSh3aGljaChyb3duYW1lcyhwaGVubykgJWluJSBuYW1lc19vZl9jb250cm9sX2NlbGxzKSksIF0KCiMjIGNoZWNrIGRpbWVuc2lvbnMKcGFzdGUoIm51bWJlciBvZiBnZW5lcyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsxXSwgIm51bWJlciBvZiBjZWxscyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsyXSkKcGFzdGUoIm51bWJlciBvZiBjb2x1bW5zIGluIGNvdW50cyIsIGRpbShwaGVubylbMl0sICJudW1iZXIgb2YgY2VsbHMgaW4gcGhlbm8iLCBkaW0ocGhlbm8pWzFdKQpgYGAKCiMjIyBSZW1vdmUgMTAgYW5kIDI3CgoxMCBhbmQgMjcgZmFpbGVkIGdlbm90eXBpbmcgYW5kIHNvIHdpbGwgYmUgcmVtb3ZlZApgYGB7cn0KIyMgZmluZCBhbGwgY2VsbHMgdGhhdCBhcmUgbGFiZWxsZWQgYXMgc3VjaApuYW1lc19vZl9nZW5vdHlwZV9mYWlsX2NlbGxzIDwtIHJvd25hbWVzKHBoZW5vWyhwaGVubyRzdWJfaWRlbnRpdHlfdXBkYXRlZCAlaW4lIGMoIkdDU0tPLTEwIiwgIldULTEwIiwgIkdDU0tPLTI3IikpLCBdKQoKIyMgd2hpY2ggZ2l2ZXMKdGFibGUoY29sbmFtZXMoY291bnRzKSAlaW4lIG5hbWVzX29mX2dlbm90eXBlX2ZhaWxfY2VsbHMpCgojIyBzdWJzZXQgCmNvdW50cyA8LSBjb3VudHNbLC13aGljaChjb2xuYW1lcyhjb3VudHMpICVpbiUgbmFtZXNfb2ZfZ2Vub3R5cGVfZmFpbF9jZWxscyldCnBoZW5vIDwtIHBoZW5vWy0od2hpY2gocm93bmFtZXMocGhlbm8pICVpbiUgbmFtZXNfb2ZfZ2Vub3R5cGVfZmFpbF9jZWxscykpLCBdCgojIyBjaGVjayBkaW1lbnNpb25zCnBhc3RlKCJudW1iZXIgb2YgZ2VuZXMgaW4gY291bnRzIiwgZGltKGNvdW50cylbMV0sICJudW1iZXIgb2YgY2VsbHMgaW4gY291bnRzIiwgZGltKGNvdW50cylbMl0pCnBhc3RlKCJudW1iZXIgb2YgY29sdW1ucyBpbiBjb3VudHMiLCBkaW0ocGhlbm8pWzJdLCAibnVtYmVyIG9mIGNlbGxzIGluIHBoZW5vIiwgZGltKHBoZW5vKVsxXSkKYGBgCgojIyMgRmlsdGVyIG5vbi1nZW5lcyBvdXQgb2YgY291bnRzCgpGaWx0ZXIgb3V0IHRoZSBRQyBjb2x1bW5zIGNvbnRhaW5lZCBpbiBjb3VudHMgdGhhdCBkbyBub3QgY29ycmVzcG9uZCB0byBnZW5lcwpgYGB7cn0KIyMgc2luY2UgdGhlIGRhdGF0YWJsZSBjdXJyZW50bHkgY29udGFpbnM6CnBhc3RlKCJUaGUgY3VycmVudCBjb3VudHMgdGFibGUgY29udGFpbnMgdGhlc2Ugbm9uLWdlbmUgcm93czoiKQpyb3duYW1lcyhjb3VudHNbLShncmVwKCJQQkFOS0EqIiwgcm93bmFtZXMoY291bnRzKSkpLCBdKQoKIyMgc3Vic2V0CiMgbWFrZSBhIGNvcHkgb2YgY291bnRzIGp1c3QgaW4gY2FzZSB0aGF0IGluZm8gaXMgdXNlZnVsIGluIGZ1dHVyZSBhbmFseXNpcwpjb3VudHNfZ2VuZXMgPC0gY291bnRzCiMgcmVtb3ZlIG5vbi1nZW5lIHJvd3MKY291bnRzIDwtIGNvdW50c1soZ3JlcCgiUEJBTktBKiIsIHJvd25hbWVzKGNvdW50cykpKSwgXQojY2hlY2sKcGFzdGUoIm51bWJlciBvZiBnZW5lcyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsxXSwgIm51bWJlciBvZiBjZWxscyBpbiBjb3VudHMiLCBkaW0oY291bnRzKVsyXSkKYGBgCgpUaGlzIDUyNDUgaW5jbHVkZXMgYWxsIHR5cGVzIG9mIGdlbmVzOgpgYGB7cn0KIyMgY2hlY2sgc2l6ZQpwYXN0ZSgiVGhlIGRpbWVuc2lvbnMgb2YgdGhlIEdURiBmaWxlIGFyZToiKQpkaW0oZ3RmWy13aGljaChndGYkVjMgPT0gIkNEUyIpLF0pCgojIyBsb29rIGF0IHBvc3NpYmxlIHR5cGVzIG9mIGdlbmVzCnBhc3RlKCJUaGUgdHlwZXMgb2YgZ2VuZXMgaW4gdGhlIGRhdGFmcmFtZSBhcmU6IikKbmFtZXModGFibGUoZ3RmJFYzKSkKYGBgCgoqKioKIyAyLiBGaWx0ZXJpbmcgey50YWJzZXR9CgojIyMgc2V0LXVwIGRhdGEKCm1ha2Ugc2V1cmF0IG9iamVjdApgYGB7cn0KIyMgbWFrZSBzZXVyYXQgb2JqZWN0CnNzMl9tdXRhbnRzIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBjb3VudHMsIHByb2plY3QgPSAiR0NTS08iLCBtaW4uY2VsbHMgPSAwLCBtaW4uZmVhdHVyZXMgPSAxLCBtZXRhLmRhdGEgPSBwaGVubykKIyBuLmIuIGNlbGxzIG11c3QgaGF2ZSBhdCBsZWFzdCAxIGdlbmUgcGVyIGNlbGwgYmVjYXVzZSB0aGlzIGNhdXNlcyBwcm9ibGVtcyBkb3duc3RyZWFtCgojIyBhZGQgZXhwZXJpbWVudCBjb2x1bW4gdG8gbWV0YSBkYXRhOgpzczJfbXV0YW50c0BtZXRhLmRhdGEkZXhwZXJpbWVudCA8LSAic3MyX211dGFudHMiCgojIyBpbnNwZWN0IG9iamVjdApzczJfbXV0YW50cwpgYGAKCmBgYHtyfQojIyBob3cgbWFueSBnZW5lcyBhcmUgbm90IGRldGVjdGVkIGF0IGFsbD8KcGFzdGUobGVuZ3RoKHdoaWNoKHJvd1N1bXMoYXMubWF0cml4KHNzMl9tdXRhbnRzQGFzc2F5cyRSTkFAY291bnRzKSkgPT0gMCkpLCAiIGdlbmVzIGFyZSBub3QgZGV0ZWN0ZWQgaW4gYW55IGNlbGwiKQpgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9CnBhc3RlKGxlbmd0aChjb2xuYW1lcyhjb3VudHMpKSAtIGxlbmd0aChjb2xuYW1lcyhhcy5tYXRyaXgoc3MyX211dGFudHNAYXNzYXlzJFJOQUBjb3VudHMpKSksICIgY2VsbHMgaGF2ZSB6ZXJvIGNvdW50cyIpCmBgYAoKIyMjIEZpbHRlcmVkIENlbGxzIFBsYXRlIEhlYXRtYXAKCnNldCB1cCBkYXRhCmBgYHtyfQojIyBsb2FkIGluIGRwbHlyIApsaWJyYXJ5KGRwbHlyKSAjZm9yIG11dGF0aW5nIHRhYmxlCgojIyBtYWtlIGRhdGFmcmFtZQpkZl9wbGF0ZW1hcCA8LSBkYXRhLmZyYW1lKHdlbGxfbmFtZSA9IHBoZW5vJHdlbGxfbmFtZV9SLCBjZWxsX25hbWUgPSByb3duYW1lcyhwaGVubyksIHJvdy5uYW1lcyA9IHJvd25hbWVzKHBoZW5vKSkKCiMjIGdldCBjZWxscyB0aGF0IGFyZSBmaWx0ZXJlZCBvdXQKY2VsbHNfa2VwdCA8LSB3aGljaChyb3duYW1lcyhkZl9wbGF0ZW1hcCkgJWluJSByb3duYW1lcyhzczJfbXV0YW50c0BtZXRhLmRhdGEpKQoKIyMgbWFrZSBleHRyYSBjb2x1bW4gaW4gcGxvdHRpbmcgZGYKZGZfcGxhdGVtYXAkY29sb3VyIDwtICJmaWx0ZXJlZF9vdXQiCmRmX3BsYXRlbWFwJGNvbG91cltjZWxsc19rZXB0XSA8LSAicGFzc2VkX1FDIgoKIyMgaW5zcGVjdApoZWFkKGRmX3BsYXRlbWFwKQpgYGAKCk1ha2UgYSB0YWJsZSBmb3IgZWFjaApgYGB7cn0KdGFibGVfcGxhdGVtYXAgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShkZl9wbGF0ZW1hcCR3ZWxsX25hbWUsIGRmX3BsYXRlbWFwJGNvbG91cikpCm5hbWVzKHRhYmxlX3BsYXRlbWFwKSA8LSBjKCJ3ZWxsIiwgImZpbHRlcmVkIiwgImZyZXF1ZW5jeSIpCgojbWFrZSBzZXBhcmF0ZSBkZnMKZGZfMSA8LSB0YWJsZV9wbGF0ZW1hcFt0YWJsZV9wbGF0ZW1hcCRmaWx0ZXJlZCA9PSAiZmlsdGVyZWRfb3V0IixdCmRmXzIgPC0gdGFibGVfcGxhdGVtYXBbdGFibGVfcGxhdGVtYXAkZmlsdGVyZWQgPT0gInBhc3NlZF9RQyIsXQoKIyBtZXJnZSB0aGVtIGJhY2sgdG9nZXRoZXIKdGFibGVfcGxhdGVtYXAgPC0gbWVyZ2UoZGZfMSwgZGZfMiwgYnkgPSAid2VsbCIsIGFsbCA9IFRSVUUpCgojIyByZW1vdmUgdGhlIGlycmVsZXZhbnQgcm93cyBhbmQgcmVuYW1lIGNvbHMgYW5kIHJlbmFtZSByb3dzCnRhYmxlX3BsYXRlbWFwIDwtIHRhYmxlX3BsYXRlbWFwWyAsYygxLDMsNSldCm5hbWVzKHRhYmxlX3BsYXRlbWFwKSA8LSBjKCJ3ZWxsIiwgImZpbHRlcmVkX291dCIsICJwYXNzZWRfUUMiKQp0YWJsZV9wbGF0ZW1hcCR3ZWxsX25hbWUgPC0gcm93bmFtZXModGFibGVfcGxhdGVtYXApCgojIyBhZGQgQTE/CiN0YWJsZV9wbGF0ZW1hcFs5NixdIDwtIGMoIkExIiwgIjAiLCAiMCIpCgojIyBhZGQgY29scyBmb3IgcGxvdHRpbmcKdGFibGVfcGxhdGVtYXAkUm93IDwtIGFzLm51bWVyaWMobWF0Y2godG91cHBlcihzdWJzdHIodGFibGVfcGxhdGVtYXAkd2VsbCwgMSwgMSkpLCBMRVRURVJTKSkKdGFibGVfcGxhdGVtYXAkQ29sdW1uIDwtIGFzLm51bWVyaWMoc3Vic3RyKHRhYmxlX3BsYXRlbWFwJHdlbGwsIDIsIDUpKQpgYGAKClBsb3QKYGBge3J9CiMjIGNhbGN1bGF0ZSBhIHBlcmNlbnRhZ2UKdGFibGVfcGxhdGVtYXAkZmlsdGVyZWRfcGMgPC0gKCh0YWJsZV9wbGF0ZW1hcCRmaWx0ZXJlZF9vdXQpLyh0YWJsZV9wbGF0ZW1hcCRmaWx0ZXJlZF9vdXQgKyB0YWJsZV9wbGF0ZW1hcCRwYXNzZWRfUUMpKSoxMDAKCiMjIGR1ZSB0byBhbiBlcnJvciBpbiB0aGUgc2NhbGVfeV9yZXZlcnNlLCB5b3UgbmVlZCB0byBtYWtlIGEgY29sdW1uIG9mICdyZXZlcnNlZCcgcm93IHZhbHVlcyB0byBwbG90CmZvcihpIGluIHNlcSgxLDgpKXsKICB0YWJsZV9wbGF0ZW1hcCRSb3dfcmV2W3RhYmxlX3BsYXRlbWFwJFJvdyA9PSBpXSA8LSBzZXEoOCwxKVtpXQp9CgojIyBvbmUgd2F5IG9mIG1hbnVhbGx5IGNvbG91cmluZyBpbiBwb2ludHMgYWZ0ZXIKIysgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9Yyh0YWJsZV9vZl9jb2xvcnNbMToyXSxjPSJncmVlbiIpKQojIyBmaW5kIHdlbGxzIHdoZXJlIGl0J3MgemVybwp6ZXJvX3dlbGxzIDwtIHRhYmxlX3BsYXRlbWFwJGZpbHRlcmVkX3BjID09IDAKdGFibGVfcGxhdGVtYXAkZmlsdGVyZWRfcGNbemVyb193ZWxsc10gPC0gTkEKCiMjIHBsb3QKc2FtcGxlX21hcF9ub19yZWFkcyA8LSBnZ3Bsb3QoZGF0YT10YWJsZV9wbGF0ZW1hcCwgYWVzKHg9Q29sdW1uLCB5PVJvd19yZXYpKSArCiAgI3NldCB1cCB0aGUgcGxhdGVtYXAgbGF5b3V0CiAgICBnZW9tX3BvaW50KGRhdGE9ZXhwYW5kLmdyaWQoc2VxKDEsIDEyKSwgc2VxKDEsIDgpKSwgYWVzKHg9VmFyMSwgeT1WYXIyKSwgY29sb3I9ImdyZXk5MCIsIGZpbGw9IndoaXRlIiwgc2hhcGU9MjEsIHNpemU9NikgKwogICNDaGFuZ2UgdGhlIHNoYXBlIGFuZCBjb2xvdXIgb2YgcG9pbnRzIGZvciBhIHZhcmlhYmxlCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBmaWx0ZXJlZF9wYykpICsKICAjY2hhbmdlIHRoZSBjb2xvdXJzCiAgICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKGd1aWRlID0gImNvbG91cmJhciIsIG5hLnZhbHVlPSJ3aGl0ZSIpICsKICAjIyBkaXBsYXkgbGVnZW5kIG9uIGJvdHRvbQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJib3R0b20iKSArCiAgI2ZpeCB0aGUgcmF0aW8gb2YgY29vcmRpbmF0ZXMKICAgIGNvb3JkX2ZpeGVkKHJhdGlvPSgxMy8xMikvKDkvOCksIHhsaW09YygwLjUsIDEyLjUpLCB5bGltPWMoMC42LCA4LjQpKSArCiAgIyBtYWtlIGludG8gYSBwbGF0ZSBwbG90CiAgICB0aGVtZV9iZGNfbWljcm90aXRlcigpICsKICAjYWRkIGxhYmVscyBmb3IgdGhlIHkgYXhpcwogICAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxLCA4KSwgbGFiZWxzID0gTEVUVEVSU1s4OjFdKSArCiAgI2FkZCBsYWJlbHMgZm9yIHRoZSB4IGF4aXMKICAgIHNjYWxlX3hfY29udGludW91cyhwb3NpdGlvbiA9ICJ0b3AiLCBicmVha3M9c2VxKDEsIDEyKSkgKwogICNBZGQgYSB0aXRsZSBhbmQgY2hhbmdlIGxhYmVsIG9mIGZpbGwKICAgIGxhYnModGl0bGU9IlRoZSBwb3NpdGlvbiBvZiBjZWxscyB3aXRoIHplcm8gY291bnRzIiAsIHNpemUgPSA2LCBjb2xvdXIgPSAicGVyY2VudGFnZSBvZiBjZWxscyBpbiB0aGlzIHdlbGwgd2l0aCB6ZXJvIGNvdW50cyIpICsKICAjcm90YXRlIGxlZ2VuZCBndWlkZSBiZWNhdXNlIG90aGVyd2lzZSB5b3UgY2FuJ3Qgc2VlIG51bWJlcnM6CiAgICBndWlkZXMoZmlsbCA9IGd1aWRlX2NvbG9yYmFyKGJhcndpZHRoID0gMC41LCBiYXJoZWlnaHQgPSAxMCwgdGl0bGU9IlZhbHVlIikpCgojIyBwcmludApzYW1wbGVfbWFwX25vX3JlYWRzCgojIyBzYXZlCmdnc2F2ZSgiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2ltYWdlc190b19leHBvcnQvcGxhdGVtYXBfbm9fY291bnQucG5nIiwgcGxvdCA9IHNhbXBsZV9tYXBfbm9fcmVhZHMsIGRldmljZSA9ICJwbmciLCBwYXRoID0gTlVMTCwgc2NhbGUgPSAxLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDAsIGxpbWl0c2l6ZSA9IFRSVUUpCgojIyB0byBtYWtlIHNjYXR0ZXJwaWUKIyNsaWJyYXJ5KCJzY2F0dGVycGllIikgIyBuZWVkZWQgZm9yIGdlb21fc2NhdHRlcnBpZQojIyB0aGVuIHVzZSB0aGlzIHJhdGhlciB0aGFuIGdlb21fcG9pbnQgYW5kIGNvbG91ciBieQojIytnZW9tX3NjYXR0ZXJwaWUoYWVzKHg9Q29sdW1uLCB5PVJvdywgZ3JvdXAgPSB3ZWxsKSwgZGF0YT10YWJsZV9wbGF0ZW1hcCwgY29scz1jKCJmaWx0ZXJlZF9vdXQiLCAicGFzc2VkX1FDIiksIGNvbG9yPU5BLCBhbHBoYT0uOCkKYGBgCgoKIyMjIEZpbHRlciBNaXRvY2hvbmRyaWFsIChGaWd1cmUgUzYpCgpNaXRvY2hvbmRyaWFsIGNlbGwgY291bnRzCmBgYHtyfQojIyBleHRyYWN0IG1pdG9jaG9uZHJpYWwgZ2VuZXMgCm1pdG9fZ2VuZXMgPC0gZ3RmW3doaWNoKGd0ZiRWMyA9PSAiclJOQSIpLF0kVjkKbWl0b19nZW5lcyA8LSBnc3ViKCI7LioiLCIiLCBnc3ViKCJnZW5lX2lkICIsICIiLCBtaXRvX2dlbmVzKSkKcGFzdGUoIlRoZXNlIGFyZSB0aGUgbWl0b2Nob25kcmlhbCBnZW5lcyIpCmhlYWQobWl0b19nZW5lcykKCiMjIG1ha2UgYSBwZXJjZW50YWdlIG1pdG9jb25kcmlhbCBmb3IgZWFjaCBjZWxsICh0aGlzIHdpbGwgd29yayBhcyBsb25nIGFzIHlvdSBmaWx0ZXIgY2VsbHMgb3V0IHdpdGggemVybyBjb3VudHMpCnNzMl9tdXRhbnRzIDwtIFBlcmNlbnRhZ2VGZWF0dXJlU2V0KHNzMl9tdXRhbnRzLCBmZWF0dXJlcyA9IHdoaWNoKHJvd25hbWVzKGNvdW50cykgJWluJSBtaXRvX2dlbmVzKSwgY29sLm5hbWUgPSAicGVyY2VudC5tdCIpCmBgYAoKcGxvdCBwZXJjZW50YWdlIG1pdG9jaG9uZHJpYWwKYGBge3J9CiMjIHBsb3QgZm9yIHBlcmNlbnRhZ2Ugb2YgbWl0b2Nob25kcmlhbCByZWFkcwp2MSA8LSBWbG5QbG90KG9iamVjdCA9IHNzMl9tdXRhbnRzLCBmZWF0dXJlcyA9ICJwZXJjZW50Lm10IiwgZ3JvdXAuYnkgPSAiaWRlbnRpdHlfdXBkYXRlZCIsIHB0LnNpemUgPSAwLjAxKSArIAogICMjIGFkZCBhIGxpbmUgd2hlcmUgd2Ugd2lsbCBmaWx0ZXIgCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTIwKSArCiAgIyMgcmVtb3ZlIGxlZ2VuZAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICMjIGNoYW5nZSBsYWJlbHMKICBsYWJzKHggPSAiR2Vub3R5cGUiLCB5ID0gIiUgTWl0b2Nob25kcmlhbCBSZWFkcyIpICsKICAjIyByZW1vdmUgcGxvdCB0aXRsZQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCgojIyBwbG90IGZvciBwZXJjZW50YWdlIG9mIG1pdG9jaG9uZHJpYWwgcmVhZHMKdjIgPC0gVmxuUGxvdChvYmplY3QgPSBzczJfbXV0YW50cywgZmVhdHVyZXMgPSAicGVyY2VudC5tdCIsIGdyb3VwLmJ5ID0gImV4cGVyaW1lbnQiLCBwdC5zaXplID0gMC4wMSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0yMCkgKwogICMjIHJlbW92ZSBsZWdlbmQKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAjIyBmcmVtb3ZlIGF4aXMgbGFiZWxzCiAgbGFicyh4PSIiLCB5ID0gIiIpICsKICAjIyByZW1vdmUgYXhpcyBlbGVtZW50cwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSkgKwogICMjIGNoYW5nZSBsYWJlbCBvbiBib3R0b20gb2YgcGxvdAogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gIkFsbCBjZWxscyIpCgojIyBwbG90IHRvZ2V0aGVyClFDX21pdG9fdmlvbGluIDwtIHYxICsgdjIgKyBwbG90X2xheW91dChuY29sID0gMiwgbnJvdyA9IDEsIHdpZHRocyA9IGMoNCwgMSksIGhlaWdodHMgPSBjKDIsIDIpKQoKIyMgcHJpbnQKUUNfbWl0b192aW9saW4KCiMjIHNhdmUKZ2dzYXZlKCIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvaW1hZ2VzX3RvX2V4cG9ydC9RQ19taXRvX3Zpb2xpbi5wbmciLCBwbG90ID0gUUNfbWl0b192aW9saW4sIGRldmljZSA9ICJwbmciLCBwYXRoID0gTlVMTCwgc2NhbGUgPSAxLCB3aWR0aCA9IDE1LCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDAsIGxpbWl0c2l6ZSA9IFRSVUUpCmBgYAoKbWFrZSBhIGRhdGFmcmFtZSBmb3IgcGxvdHRpbmcKYGBge3J9CmRmIDwtIGRhdGEuZnJhbWUobkNvdW50ID0gbG9nMTAoc3MyX211dGFudHNAbWV0YS5kYXRhJG5Db3VudF9STkEpLCBuR2VuZXMgPSBzczJfbXV0YW50c0BtZXRhLmRhdGEkbkZlYXR1cmVfUk5BLCBpZGVudGl0eSA9IHNzMl9tdXRhbnRzQG1ldGEuZGF0YSRpZGVudGl0eV91cGRhdGVkLCBpZGVudGl0eV9nZW5lID0gc3MyX211dGFudHNAbWV0YS5kYXRhJGlkZW50aXR5X2dlbmVfdXBkYXRlZCwgcGVyY2VudF9tdCA9IHNzMl9tdXRhbnRzQG1ldGEuZGF0YSRwZXJjZW50Lm10KQpgYGAKCldoZXJlIGRvIG1pdGNob25kcmlhbCBwb29yIGNlbGxzIGxpZT8KYGBge3J9CiMjIG1ha2UgZXh0cmEgY29sIGZvciBmaWx0ZXJlZCB2YWx1ZXM6CmZpbHRlcmVkX291dF9jZWxscyA8LSB3aGljaChkZiRwZXJjZW50X210ID4gMjApIAoKIyMgcGxvdApRQ19taXRvX2dyYXBoIDwtIGdncGxvdChkZiwgYWVzKHggPSBuQ291bnQsIHkgPSBuR2VuZXMpKSArIAogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjQpICsKICBzY2FsZV9zaXplKHJhbmdlID0gYygwLjEsNCkpICsKICAjZ2VvbV9ydWcoKSArIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIk51bWJlciBvZiBEZXRlY3RlZCBHZW5lcyIpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAibG9nMTAoTnVtYmVyIG9mIFRvdGFsIENvdW50cykiKSArCiAgc2NhbGVfY29sb3JfdmlyaWRpcyhvcHRpb24gPSAiRCIpICsKICB0aGVtZV9wdWJyKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PTMpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MjIwKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTMzMDApICsKICAjYW5ub3RhdGUgc2VsZWN0ZWQgcG9pbnRzCiAgYW5ub3RhdGUoInBvaW50IiwgZGYkbkNvdW50W2ZpbHRlcmVkX291dF9jZWxsc10sIGRmJG5HZW5lc1tmaWx0ZXJlZF9vdXRfY2VsbHNdLCBzaXplID0gMiwgY29sb3VyID0gIm9yYW5nZSIpCgojIyBhZGQgdGhpcyB0byBnZW1vX3BvaW50IGlmIG5lZWRlZDogYWVzKGNvbG91ciA9IHBlcmNlbnRfbXQsIHNpemUgPSBwZXJjZW50X210KQoKIyMgcHJpbnQKUUNfbWl0b19ncmFwaAoKIyMgc2F2ZQpnZ3NhdmUoIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9pbWFnZXNfdG9fZXhwb3J0L1FDX21pdG9fZ3JhcGgucG5nIiwgcGxvdCA9IFFDX21pdG9fZ3JhcGgsIGRldmljZSA9ICJwbmciLCBwYXRoID0gTlVMTCwgc2NhbGUgPSAxLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDAsIGxpbWl0c2l6ZSA9IFRSVUUpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSAxMH0KIyMgcGxvdCAxCnBsb3QxIDwtIEZlYXR1cmVTY2F0dGVyKHNzMl9tdXRhbnRzLCBmZWF0dXJlMSA9ICJuQ291bnRfUk5BIiwgZmVhdHVyZTIgPSAicGVyY2VudC5tdCIsIHB0LnNpemUgPSAwLjAxLCBncm91cC5ieSA9ICJpZGVudGl0eV91cGRhdGVkIikKCiMjIHBsb3QgMgpwbG90MiA8LSBGZWF0dXJlU2NhdHRlcihzczJfbXV0YW50cywgZmVhdHVyZTEgPSAibkNvdW50X1JOQSIsIGZlYXR1cmUyID0gIm5GZWF0dXJlX1JOQSIsIHB0LnNpemUgPSAwLjAxLCBncm91cC5ieSA9ICJpZGVudGl0eV91cGRhdGVkIikKCiMjIHBsb3QgdG9nZXRoZXIKcGxvdDEgKyBwbG90MgpgYGAKCiMjIEZpbHRlciBwb29yIHF1YWxpdHkgY2VsbHMKCmluIHRoZSBNQ0EgcGFwZXI6CiJDZWxscyB3aXRoIGZld2VyIHRoYW4gMTAwMCBnZW5lcyBwZXIgY2VsbCBhbmQgMjUwMCByZWFkcyBwZXIgY2VsbCB3ZXJlIHJlbW92ZWQgZnJvbSB0aGUgbGl2ZXItc3RhZ2UgcGFyYXNpdGVzLCB0cm9waG96b2l0ZXMsIG1hbGUgYW5kIGZlbWFsZSBnYW1ldG9jeXRlcywgb29raW5ldGVzLCBvb2tpbmV0ZXMvb29jeXN0cywgYW5kIG9vY3lzdCBzdGFnZXMuIENlbGxzIHdpdGggZmV3ZXIgdGhhbiA1MDAgZ2VuZXMgcGVyIGNlbGwgYW5kIDI1MDAgcmVhZHMgcGVyIGNlbGwgd2VyZSByZW1vdmVkIGZyb20gc2NoaXpvbnRzIGFuZCBpbmplY3RlZCBzcG9yb3pvaXRlcy4gQ2VsbHMgd2l0aCBmZXdlciB0aGFuIDQwIGdlbmVzIHBlciBjZWxsIGFuZCAxMDAwIHJlYWRzIHBlciBjZWxsIHdlcmUgcmVtb3ZlZCBmcm9tIG1lcm96b2l0ZXMsIHJpbmdzLCBhbmQgZ2xhbmQgc3Bvcm96b2l0ZXMgKGZpZy4gUzIgYW5kIHRhYmxlIFMxKS4gQWRkaXRpb25hbGx5LCB3ZSByZW1vdmVkIGdlbmVzIGZyb20gZnVydGhlciBhbmFseXNpcyB0aGF0IHdlcmUgZGV0ZWN0ZWQgaW4gZmV3ZXIgdGhhbiB0d28gY2VsbHMgYWNyb3NzIHRoZSBlbnRpcmUgZGF0YXNldC4gVGhlIGZpbmFsIGRhdGFzZXQgY29udGFpbmVkIDE3ODcgaGlnaC1xdWFsaXR5IHNpbmdsZSBjZWxscyBmcm9tIDE5ODIgc2VxdWVuY2VkIGNlbGxzIGFuZCA1MTU2IGdlbmVzIG91dCBvZiA1MjQ1IGdlbmVzIHdpdGggYW5ub3RhdGVkIHRyYW5zY3JpcHRzLiIKCnNvIHVzZToKMTAwMCByZWFkcyBwZXIgY2VsbCAmIDQwIGdlbmVzIHBlciBjZWxsIGFzIGFic29sdXRlIG1pbmltdW1zCgpgYGB7ciwgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDh9CiMjIHBsb3QgbWFpbiBkb3RwbG90CnBsb3QxIDwtIGdncGxvdChkZiwgYWVzKHggPSBuQ291bnQsIHkgPSBuR2VuZXMsIGNvbG9yID0gaWRlbnRpdHkpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gaWRlbnRpdHkpLCBzaXplID0gMC4xKSArCiAgZ2VvbV9ydWcoKSArIAogIHNjYWxlX3lfY29udGludW91cyhuYW1lID0gIk51bWJlciBvZiBEZXRlY3RlZCBHZW5lcyIpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAibG9nMTAoTnVtYmVyIG9mIFRvdGFsIENvdW50cykiKSArIAogIHRoZW1lX3B1YnIoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9MykgKwogIGdlb21faGxpbmUoeWludGVyY2VwdD0yMjApICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MzMwMCkKCiMjIHBsb3QgZGVuc2l0eSBwbG90IHgKZGVuczEgPC0gZ2dwbG90KGRmLCBhZXMoeCA9IG5Db3VudCwgZmlsbCA9IGlkZW50aXR5KSkgKyAKICBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKIyMgcGxvdCBkZW5zaXR5IHBsb3QgeQpkZW5zMiA8LSBnZ3Bsb3QoZGYsIGFlcyh4ID0gbkdlbmVzLCBmaWxsID0gaWRlbnRpdHkpKSArIAogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuMikgKyAKICB0aGVtZV92b2lkKCkgKyAKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgCiAgY29vcmRfZmxpcCgpCgojIyBwbG90IHRvZ2V0aGVyClFDX2NvbXBvc2l0ZV9wbG90IDwtIGRlbnMxICsgcGxvdF9zcGFjZXIoKSArIHBsb3QxICsgZGVuczIgKyBwbG90X2xheW91dChuY29sID0gMiwgbnJvdyA9IDIsIHdpZHRocyA9IGMoNCwgMSksIGhlaWdodHMgPSBjKDEsIDQpKQoKIyMgcHJpbnQKUUNfY29tcG9zaXRlX3Bsb3QKCiMjIHNhdmUKZ2dzYXZlKCIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvaW1hZ2VzX3RvX2V4cG9ydC9RQ19jb21wb3NpdGVfcGxvdC5wbmciLCBwbG90ID0gUUNfY29tcG9zaXRlX3Bsb3QsIGRldmljZSA9ICJwbmciLCBwYXRoID0gTlVMTCwgc2NhbGUgPSAxLCB3aWR0aCA9IDIwLCBoZWlnaHQgPSAyMCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDAsIGxpbWl0c2l6ZSA9IFRSVUUpCmBgYAoKKioqCiMgMy4gQW5hbHlzaXMgey50YWJzZXR9CgojIyMgRmluYWwgZmlsdGVyCmZpbHRlciBvdXQgY2VsbHMKYGBge3J9CiMjIHN1YnNldApzczJfbXV0YW50c19maW5hbCA8LSBzdWJzZXQoc3MyX211dGFudHMsIHN1YnNldCA9IG5GZWF0dXJlX1JOQSA+IDIyMCAmIG5GZWF0dXJlX1JOQSA8IDMzMDAgJiBwZXJjZW50Lm10IDwgMjAgJiBuQ291bnRfUk5BID4gMTAwMCkKCiMjIGluc3BlY3QgcmVzdWx0YW50IG9iamVjdApzczJfbXV0YW50c19maW5hbApgYGAKCmBgYHtyLCBlY2hvID0gRkFMU0V9CnBhc3RlKGxlbmd0aChjb2xuYW1lcyhzczJfbXV0YW50c0Bhc3NheXMkUk5BQGNvdW50cykpIC0gbGVuZ3RoKGNvbG5hbWVzKHNzMl9tdXRhbnRzX2ZpbmFsQGFzc2F5cyRSTkFAY291bnRzKSksICIgY2VsbHMgYXJlIHJlbW92ZWQgYnkgdGhlc2UgZmlsdGVycyIpCmBgYAoKIyMjIFBsYXRlbWFwIGhlYXRtYXAgZm9yIGZhaWxlZCBjZWxscwoKc2V0IHVwIGRhdGEKYGBge3J9CiMjIG1ha2UgZGF0YWZyYW1lCmRmX3BsYXRlbWFwIDwtIGRhdGEuZnJhbWUod2VsbF9uYW1lID0gcGhlbm8kd2VsbF9uYW1lX1IsIGNlbGxfbmFtZSA9IHJvd25hbWVzKHBoZW5vKSwgcm93Lm5hbWVzID0gcm93bmFtZXMocGhlbm8pKQoKIyMgZ2V0IGNlbGxzIHRoYXQgYXJlIGZpbHRlcmVkIG91dApjZWxsc19rZXB0IDwtIHdoaWNoKHJvd25hbWVzKGRmX3BsYXRlbWFwKSAlaW4lIHJvd25hbWVzKHNzMl9tdXRhbnRzX2ZpbmFsQG1ldGEuZGF0YSkpCgojIyBtYWtlIGV4dHJhIGNvbHVtbiBpbiBwbG90dGluZyBkZgpkZl9wbGF0ZW1hcCRjb2xvdXIgPC0gImZpbHRlcmVkX291dCIKZGZfcGxhdGVtYXAkY29sb3VyW2NlbGxzX2tlcHRdIDwtICJwYXNzZWRfUUMiCgojIyBpbnNwZWN0CmhlYWQoZGZfcGxhdGVtYXApCmBgYAoKTWFrZSBhIHRhYmxlIGZvciBlYWNoCmBgYHtyfQp0YWJsZV9wbGF0ZW1hcCA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKGRmX3BsYXRlbWFwJHdlbGxfbmFtZSwgZGZfcGxhdGVtYXAkY29sb3VyKSkKbmFtZXModGFibGVfcGxhdGVtYXApIDwtIGMoIndlbGwiLCAiZmlsdGVyZWQiLCAiZnJlcXVlbmN5IikKCiMgbWFrZSBzZXBhcmF0ZSBkZnMKZGZfMSA8LSB0YWJsZV9wbGF0ZW1hcFt0YWJsZV9wbGF0ZW1hcCRmaWx0ZXJlZCA9PSAiZmlsdGVyZWRfb3V0IixdCmRmXzIgPC0gdGFibGVfcGxhdGVtYXBbdGFibGVfcGxhdGVtYXAkZmlsdGVyZWQgPT0gInBhc3NlZF9RQyIsXQoKIyBtZXJnZSB0aGVtIGJhY2sgdG9nZXRoZXIKdGFibGVfcGxhdGVtYXAgPC0gbWVyZ2UoZGZfMSwgZGZfMiwgYnkgPSAid2VsbCIsIGFsbCA9IFRSVUUpCgojIyByZW1vdmUgdGhlIGlycmVsZXZhbnQgcm93cyBhbmQgcmVuYW1lIGNvbHMgYW5kIHJlbmFtZSByb3dzCnRhYmxlX3BsYXRlbWFwIDwtIHRhYmxlX3BsYXRlbWFwWyAsYygxLDMsNSldCm5hbWVzKHRhYmxlX3BsYXRlbWFwKSA8LSBjKCJ3ZWxsIiwgImZpbHRlcmVkX291dCIsICJwYXNzZWRfUUMiKQp0YWJsZV9wbGF0ZW1hcCR3ZWxsX25hbWUgPC0gcm93bmFtZXModGFibGVfcGxhdGVtYXApCgojIyBhZGQgY29scyBmb3IgcGxvdHRpbmcKdGFibGVfcGxhdGVtYXAkUm93IDwtIGFzLm51bWVyaWMobWF0Y2godG91cHBlcihzdWJzdHIodGFibGVfcGxhdGVtYXAkd2VsbCwgMSwgMSkpLCBMRVRURVJTKSkKdGFibGVfcGxhdGVtYXAkQ29sdW1uIDwtIGFzLm51bWVyaWMoc3Vic3RyKHRhYmxlX3BsYXRlbWFwJHdlbGwsIDIsIDUpKQoKIyMgaW5zcGVjdDoKaGVhZCh0YWJsZV9wbGF0ZW1hcCkKYGBgCgpgYGB7cn0KIyMgY2FsY3VsYXRlIHBlcmNlbnRhZ2UKdGFibGVfcGxhdGVtYXAkZmlsdGVyZWRfcGMgPC0gKCh0YWJsZV9wbGF0ZW1hcCRmaWx0ZXJlZF9vdXQpLyh0YWJsZV9wbGF0ZW1hcCRmaWx0ZXJlZF9vdXQgKyB0YWJsZV9wbGF0ZW1hcCRwYXNzZWRfUUMpKSoxMDAKCiMjIGR1ZSB0byBhbiBlcnJvciBpbiB0aGUgc2NhbGVfeV9yZXZlcnNlLCB5b3UgbmVlZCB0byBtYWtlIGEgY29sdW1uIG9mICdyZXZlcnNlZCcgcm93IHZhbHVlcyB0byBwbG90CmZvcihpIGluIHNlcSgxLDgpKXsKICB0YWJsZV9wbGF0ZW1hcCRSb3dfcmV2W3RhYmxlX3BsYXRlbWFwJFJvdyA9PSBpXSA8LSBzZXEoOCwxKVtpXQp9CgojIyBvbmUgd2F5IG9mIG1hbnVhbGx5IGNvbG91cmluZyBpbiBwb2ludHMgYWZ0ZXIKIysgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXM9Yyh0YWJsZV9vZl9jb2xvcnNbMToyXSxjPSJncmVlbiIpKQojIyBmaW5kIHdlbGxzIHdoZXJlIGl0J3MgemVybwp6ZXJvX3dlbGxzIDwtIHRhYmxlX3BsYXRlbWFwJGZpbHRlcmVkX3BjID09IDAKdGFibGVfcGxhdGVtYXAkZmlsdGVyZWRfcGNbemVyb193ZWxsc10gPC0gTkEKCiMjIHBsb3QKc2FtcGxlX21hcCA8LSBnZ3Bsb3QoZGF0YT10YWJsZV9wbGF0ZW1hcCwgYWVzKHg9Q29sdW1uLCB5PVJvdykpICsKICAjc2V0IHVwIHRoZSBwbGF0ZW1hcCBsYXlvdXQKICAgIGdlb21fcG9pbnQoZGF0YT1leHBhbmQuZ3JpZChzZXEoMSwgMTIpLCBzZXEoMSwgOCkpLCBhZXMoeD1WYXIxLCB5PVZhcjIpLCBjb2xvcj0iZ3JleTkwIiwgZmlsbD0id2hpdGUiLCBzaGFwZT0yMSwgc2l6ZT02KSArCiAgI0NoYW5nZSB0aGUgc2hhcGUgYW5kIGNvbG91ciBvZiBwb2ludHMgZm9yIGEgdmFyaWFibGUKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBmaWx0ZXJlZF9wYykpICsKICAjY2hhbmdlIHRoZSBjb2xvdXJzCiAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfYyhndWlkZSA9ICJjb2xvdXJiYXIiLCBuYS52YWx1ZT0id2hpdGUiKSArCiAgI2ZpeCB0aGUgcmF0aW8gb2YgY29vcmRpbmF0ZXMKICAgIGNvb3JkX2ZpeGVkKHJhdGlvPSgxMy8xMikvKDkvOCksIHhsaW09YygwLjUsIDEyLjUpLCB5bGltPWMoMC41LCA4LjUpKSArCiAgI2FkZCBsYWJlbHMgZm9yIHRoZSB5IGF4aXMKICAgIHNjYWxlX3lfcmV2ZXJzZShicmVha3M9c2VxKDEsIDgpLCBsYWJlbHM9TEVUVEVSU1sxOjhdKSArCiAgI2FkZCBsYWJlbHMgZm9yIHRoZSB4IGF4aXMKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKDEsIDEyKSkgKwogICNBZGQgYSB0aXRsZQogICAgbGFicyh0aXRsZT0iVGhlIHBvc2l0aW9uIG9mIGNlbGxzIHRoYXQgZmFpbGVkIFFDIiAsIHNpemUgPSA2LCBjb2xvdXIgPSAicGVyY2VudGFnZSBvZiBjZWxscyBpbiB0aGlzIHdlbGwgdGhhdCBmYWlsZWQgUUMiKSArCiAgI3JvdGF0ZSBsZWdlbmQgZ3VpZGUgYmVjYXVzZSBvdGhlcndpc2UgeW91IGNhbid0IHNlZSBudW1iZXJzOgogICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9jb2xvcmJhcihiYXJ3aWR0aCA9IDAuNSwgYmFyaGVpZ2h0ID0gMTAsIHRpdGxlPSJWYWx1ZSIpKSArCiAgI2NoYW5nZSB0aGUgY29sb3VycwogICAgI3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiSG9lY2hzdCI9ImJsdWUiLCAiSG9lc2NodCIgPSAiYmx1ZSIsICJtQ2hlcnJ5Ij0icmVkIiwgIkdGUCI9ImdyZWVuIikpICsKICAjIG1ha2UgbWltbmltdW0gcG9pbnQgc2l6ZSBiaWdnZXIKICAgICNzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDIsMTApKSArCiAgIyBtYWtlIGludG8gYSBwbGF0ZSBwbG90CiAgICB0aGVtZV9iZGNfbWljcm90aXRlcigpCgojIyBwcmludApzYW1wbGVfbWFwCgojIyBzYXZlCmdnc2F2ZSgiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2ltYWdlc190b19leHBvcnQvcGxhdGVtYXBfZmlsdGVyZWQucG5nIiwgcGxvdCA9IHNhbXBsZV9tYXAsIGRldmljZSA9ICJwbmciLCBwYXRoID0gTlVMTCwgc2NhbGUgPSAxLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDAsIGxpbWl0c2l6ZSA9IFRSVUUpCgojIyB0byBtYWtlIHNjYXR0ZXJwaWUKIyNsaWJyYXJ5KCJzY2F0dGVycGllIikgIyBuZWVkZWQgZm9yIGdlb21fc2NhdHRlcnBpZQojIyB0aGVuIHVzZSB0aGlzIHJhdGhlciB0aGFuIGdlb21fcG9pbnQgYW5kIGNvbG91ciBieQojIytnZW9tX3NjYXR0ZXJwaWUoYWVzKHg9Q29sdW1uLCB5PVJvdywgZ3JvdXAgPSB3ZWxsKSwgZGF0YT10YWJsZV9wbGF0ZW1hcCwgY29scz1jKCJmaWx0ZXJlZF9vdXQiLCAicGFzc2VkX1FDIiksIGNvbG9yPU5BLCBhbHBoYT0uOCkKYGBgCgpgYGB7cn0KcFBsYXRlIDwtIGdncGxvdChkYXRhID0gdGFibGVfcGxhdGVtYXAsIGFlcyh4ID0gQ29sdW1uLCB5ID0gUm93KSkgKwpnZW9tX3BvaW50KGRhdGEgPSBleHBhbmQuZ3JpZChDb2x1bW4gPSBzZXEoMSwxMiksIFJvdyA9IHNlcSgxLDgpKSwgY29sb3IgPSAiZ3JleTkwIiwgZmlsbCA9ICJ3aGl0ZSIsIHNoYXBlID0gMjEsIHNpemUgPSA4KSArCmdlb21fcG9pbnQoYWVzKGNvbG9yID0gZmlsdGVyZWRfcGMpLCBzaXplID0gOSkgKwpsYWJzKHRpdGxlID0gIlBsYXRlIExheW91dCBmb3IgTXkgRXhwZXJpbWVudCIsIHN1YnRpdGxlID0gIjI1IE1hcmNoIDIwMTYiKSArCmNvb3JkX2ZpeGVkKHJhdGlvID0gKDEzLzEyKS8oOS84KSwgeGxpbSA9IGMoMC41LCAxMi41KSwgeWxpbSA9IGMoMC42LCA4LjQpKSArIHRoZW1lX2JkY19taWNyb3RpdGVyKCkgKyBzY2FsZV94X2NvbnRpbnVvdXMocG9zaXRpb24gPSAidG9wIiwgYnJlYWtzID0gc2VxKDEsIDEyKSkgICsKdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsgZ3VpZGVzKHNoYXBlID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDMpKSwKY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMykpKSArIHNjYWxlX3lfY29udGludW91cyhicmVha3MgPSBzZXEoMSwgOCksIGxhYmVscyA9IExFVFRFUlNbMTo4XSkKCnBQbGF0ZQpgYGAKCgoKCmdldCBhIGJhciBncmFwaCBvZiB0aGlzIHRvbwpgYGB7cn0KdG90YWxfMCA8LSB0YWJsZV9wbGF0ZW1hcFt3aGljaCh0YWJsZV9wbGF0ZW1hcCRSb3cgJWluJSBjKDEsOCkgfCB0YWJsZV9wbGF0ZW1hcCRDb2x1bW4gJWluJSBjKDEsMTIpKSwgXQogIAp0b3RhbF8xIDwtIHRhYmxlX3BsYXRlbWFwW3doaWNoKHRhYmxlX3BsYXRlbWFwJFJvdyAlaW4lIGMoMiw3KSB8IHRhYmxlX3BsYXRlbWFwJENvbHVtbiAlaW4lIGMoMiwxMSkpLCBdCnRvdGFsXzEgPC0gdG90YWxfMVstd2hpY2godG90YWxfMSR3ZWxsICVpbiUgdG90YWxfMCR3ZWxsKSxdCgp0b3RhbF8yIDwtIHRhYmxlX3BsYXRlbWFwW3doaWNoKHRhYmxlX3BsYXRlbWFwJFJvdyAlaW4lIGMoMyw2KSB8IHRhYmxlX3BsYXRlbWFwJENvbHVtbiAlaW4lIGMoMywxMCkpLCBdCnRvdGFsXzIgPC0gdG90YWxfMlstd2hpY2godG90YWxfMiR3ZWxsICVpbiUgdG90YWxfMCR3ZWxsIHwgdG90YWxfMiR3ZWxsICVpbiUgdG90YWxfMSR3ZWxsKSxdCgp0b3RhbF8zIDwtIHRhYmxlX3BsYXRlbWFwW3doaWNoKHRhYmxlX3BsYXRlbWFwJFJvdyAlaW4lIGMoNCw1KSB8IHRhYmxlX3BsYXRlbWFwJENvbHVtbiAlaW4lIGMoNCw5KSksIF0KdG90YWxfMyA8LSB0b3RhbF8zWy13aGljaCh0b3RhbF8zJHdlbGwgJWluJSB0b3RhbF8wJHdlbGwgfCB0b3RhbF8zJHdlbGwgJWluJSB0b3RhbF8xJHdlbGwgfCB0b3RhbF8zJHdlbGwgJWluJSB0b3RhbF8yJHdlbGwpLF0KCiMjIGNyZWF0ZSBhIGRhdGFmcmFtZSB3aGljaCBjYWxjdWxhdGVzIHRoZSBwZXJjZW50YWdlIGZhaWxlZCBmb3IgZWFjaCBkaXN0YW5jZSBmcm9tIHRoZSBlZGdlCmZyZXF1ZW5jeV9vZl9mYWlsZWRfY2VsbHMgPC0gZGF0YS5mcmFtZShwZXJjZW50YWdlX2ZhaWxlZCA9IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bSh0b3RhbF8wJGZpbHRlcmVkX291dCkgLyAoc3VtKHRvdGFsXzAkcGFzc2VkX1FDKSArIHN1bSh0b3RhbF8wJGZpbHRlcmVkX291dCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bSh0b3RhbF8xJGZpbHRlcmVkX291dCkgLyAoc3VtKHRvdGFsXzEkcGFzc2VkX1FDKSArIHN1bSh0b3RhbF8xJGZpbHRlcmVkX291dCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bSh0b3RhbF8yJGZpbHRlcmVkX291dCkgLyAoc3VtKHRvdGFsXzIkcGFzc2VkX1FDKSArIHN1bSh0b3RhbF8yJGZpbHRlcmVkX291dCkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bSh0b3RhbF8zJGZpbHRlcmVkX291dCkgLyAoc3VtKHRvdGFsXzMkcGFzc2VkX1FDKSArIHN1bSh0b3RhbF8zJGZpbHRlcmVkX291dCkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICkpCgojIyBuZWF0ZW4gdGhlIGRhdGFmcmFtZQpmcmVxdWVuY3lfb2ZfZmFpbGVkX2NlbGxzJGRpc3RhbmNlX2Zyb21fZWRnZSA8LSBjKDAsMSwyLDMpCmBgYAoKcGxvdAoKYGBge3J9CnBvc2l0aW9uX3FjX2ZhaWwgPC0gZ2dwbG90KGZyZXF1ZW5jeV9vZl9mYWlsZWRfY2VsbHMsIGFlcyh4PWRpc3RhbmNlX2Zyb21fZWRnZSwgeT1wZXJjZW50YWdlX2ZhaWxlZCkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGw9ImJsYWNrIikrCiAgdGhlbWVfY2xhc3NpYygpICsKICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkgKwogICMjIGNoYW5nZSB0aGUgYXhpcyB0aXRsZXMKICBsYWJzKHk9ICJDZWxscyB0aGF0IGZhaWxlZCBRQyAoJSkiLCB4ID0gIk51bWJlciBvZiB3ZWxscyBmcm9tIHRoZSBlZGdlIG9mIHRoZSBwbGF0ZSIpICsKICAjIyBwcmV2ZW50IHRoZSB0aXRsZSBnb2luZyBvZmYgdGhlIGVkZ2Ugb2YgdGhlIHBsb3QKICBjb29yZF9jYXJ0ZXNpYW4oY2xpcCA9ICdvZmYnKQoKIyMgc2F2ZQpnZ3NhdmUoIn4vaW1hZ2VzX3RvX2V4cG9ydC9RQ19mYWlsZWRfcG9zaXRpb24ucG5nIiwgcGxvdCA9IHBvc2l0aW9uX3FjX2ZhaWwsIGRldmljZSA9ICJwbmciLCBwYXRoID0gTlVMTCwgc2NhbGUgPSAxLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMCwgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDAsIGxpbWl0c2l6ZSA9IFRSVUUpCgojIyBwbG90CnBvc2l0aW9uX3FjX2ZhaWwKYGBgCgoKIyMjIE1hcHBpbmcgUGxvdCAoRmlndXJlIFM2QSkKCnByZXBhcmUKYGBge3J9CiMjIG1ha2UgZGF0YWZyYW1lCmRmX21hcHBpbmdfcmF0ZXNfaGlzYXQgPC0gZGF0YS5mcmFtZShhbGlnbm1lbnRfcmF0ZSA9IHBoZW5vJG92ZXJhbGxfaGlzYXQyX2FsaWdubWVudF9yYXRlLCBjZWxsX25hbWUgPSByb3duYW1lcyhwaGVubyksIHJvdy5uYW1lcyA9IHJvd25hbWVzKHBoZW5vKSkKCiMjIGdldCBjZWxscyB0aGF0IGFyZSBmaWx0ZXJlZCBvdXQKY2VsbHNfZmlsdGVyZWQgPC0gd2hpY2gocm93bmFtZXMoZGZfbWFwcGluZ19yYXRlc19oaXNhdCkgJWluJSByb3duYW1lcyhzczJfbXV0YW50c19maW5hbEBtZXRhLmRhdGEpKQoKIyMgbWFrZSBleHRyYSBjb2x1bW4gaW4gcGxvdHRpbmcgZGYKZGZfbWFwcGluZ19yYXRlc19oaXNhdCRjb2xvdXIgPC0gIkZhaWxlZCBRQyIKZGZfbWFwcGluZ19yYXRlc19oaXNhdCRjb2xvdXJbY2VsbHNfZmlsdGVyZWRdIDwtICJQYXNzZWQgUUMiCmBgYAoKcGxvdApgYGB7ciwgZmlnLndpZHRoID0gMjIsIGZpZy5oZWlnaHQgPSA1fQojIyBwbG90Cm1hcHBpbmdfcmF0ZV9wbG90IDwtIGdncGxvdChkZl9tYXBwaW5nX3JhdGVzX2hpc2F0LCBhZXMoeCA9IHJlb3JkZXIoY2VsbF9uYW1lLGFsaWdubWVudF9yYXRlLHN1bSksIHk9YWxpZ25tZW50X3JhdGUsIGZpbGwgPSBjb2xvdXIpKSArCiAgZ2VvbV9jb2woKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogIGxhYnMoeD0iQ2VsbHMiLCB5ID0gIk92ZXJhbGwgQWxpZ25tZW50IFJhdGUgKCUpIiwgc2l6ZSA9IDE1LCBmaWxsID0gIlFDIFJlc3VsdCIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkgKwogICMjIGNoYW5nZSB0aGUgY29sb3VycwogICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygicmVkMiIsICJncmVlbjQiKSkKCiMjIHNhdmUKZ2dzYXZlKCIvVXNlcnMvQW5keS9HQ1NLTy9HQ1NLT19hbmFseXNpc19naXQvaW1hZ2VzX3RvX2V4cG9ydC9RQ19tYXBwaW5nX3JhdGUuZXBzIiwgcGxvdCA9IG1hcHBpbmdfcmF0ZV9wbG90LCBkZXZpY2UgPSAiZXBzIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQoKIyMgcGxvdAptYXBwaW5nX3JhdGVfcGxvdApgYGAKCiMjIyMgUmVjb3ZlcnkgcGxvdHMKCkhvdyBtYW55IGNlbGxzIGFyZSByZWNvdmVyZWQgcGVyIGNvbmRpdGlvbj8KYGBge3J9CiMjIGV4dHJhY3QgZGF0YQpkZl9jZWxsc19yZWNvdmVyZWQgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShzczJfbXV0YW50c19maW5hbEBtZXRhLmRhdGEkc3ViX2lkZW50aXR5X3VwZGF0ZWQpKQpkZl9jZWxsc19wcm9maWxlZCA8LSBhcy5kYXRhLmZyYW1lKHRhYmxlKHBoZW5vJHN1Yl9pZGVudGl0eV91cGRhdGVkKSkKCiMjIG1ha2UgYSBkZiBvZiB0aGUgbWV0cmljcwpkZl9jZWxsc19yZWNvdmVyZWQgPC0gbWVyZ2UoZGZfY2VsbHNfcmVjb3ZlcmVkLCBkZl9jZWxsc19wcm9maWxlZCwgYnkgPSAiVmFyMSIpCm5hbWVzKGRmX2NlbGxzX3JlY292ZXJlZCkgPC0gYygiZ2Vub3R5cGUiLCAicmVjb3ZlcmVkIiwgInByb2ZpbGVkIikKCiMjIGNhbGN1bGF0ZSBwZXJlY2VudGFnZQpkZl9jZWxsc19yZWNvdmVyZWQkcmVjb3ZlcmVkX3BjIDwtIChkZl9jZWxsc19yZWNvdmVyZWQkcmVjb3ZlcmVkL2RmX2NlbGxzX3JlY292ZXJlZCRwcm9maWxlZCkqMTAwCgojIyByb3VuZCB1cCBwZXJjZW50YWdlIGZvciBsYWJlbHMKZGZfY2VsbHNfcmVjb3ZlcmVkJHJlY292ZXJlZF9wY19yb3VuZGVkIDwtIHNpZ25pZihkZl9jZWxsc19yZWNvdmVyZWQkcmVjb3ZlcmVkX3BjLCAyKQpkZl9jZWxsc19yZWNvdmVyZWQkcmVjb3ZlcmVkX3BjX3JvdW5kZWQgPC0gcGFzdGUwKGRmX2NlbGxzX3JlY292ZXJlZCRyZWNvdmVyZWRfcGNfcm91bmRlZCwgIiAlIikKCiMjIG1ha2UgYSBjb2x1bW4gZm9yIG51bWJlciBvZiBjZWxscyBhbm5vdGF0aW9uCmRmX2NlbGxzX3JlY292ZXJlZCRudW1iZXJfY2VsbHNfYW5ub3RhdGlvbiA8LSBwYXN0ZTAoIm4gPSAiLCBkZl9jZWxsc19yZWNvdmVyZWQkcmVjb3ZlcmVkKQoKIyMgaW5zcGVjdCBkYXRhZnJhbWUKZGZfY2VsbHNfcmVjb3ZlcmVkCmBgYAoKYGBge3J9CiMjcGxvdApRQ19ieV9nZW5vdHlwZSA8LSBnZ3Bsb3QoZGZfY2VsbHNfcmVjb3ZlcmVkLCBhZXMoeD1nZW5vdHlwZSwgeT1yZWNvdmVyZWRfcGMgLGZpbGw9Z2Vub3R5cGUpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgeWxpbSgwLCAxMDApICsKICAjc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIikgKwogIGdlb21fdGV4dChhZXMobGFiZWw9cmVjb3ZlcmVkX3BjX3JvdW5kZWQsIHZqdXN0PTAuNSwgaGp1c3QgPSAxLjUpKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbD1udW1iZXJfY2VsbHNfYW5ub3RhdGlvbiwgdmp1c3Q9MC41LCBoanVzdCA9IC0wLjA1KSkgKwogIGxhYnMoeSA9ICJQZXJjZW50YWdlIG9mIGNlbGxzIHJlY292ZXJlZCIsIHggPSAiR2Vub3R5cGUiKSArCiAgY29vcmRfZmxpcChjbGlwID0gIm9mZiIpICsKICB0aGVtZV9jbGFzc2ljKCkgKwogICMjIHJlbW92ZSBsZWdlbmQgKyBhZGQgYm9yZGVyIHNvIGl0IGRvZXNuJ3QgY2xpcCB0aGUgYW5ub3RhdGlvbiAKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiLCBwbG90Lm1hcmdpbiA9IHVuaXQoYygxLDMsMSwzKSwgImxpbmVzIikpCgojIyBwbG90ClFDX2J5X2dlbm90eXBlCgojIyBzYXZlCmdnc2F2ZSgiL1VzZXJzL0FuZHkvR0NTS08vR0NTS09fYW5hbHlzaXNfZ2l0L2ltYWdlc190b19leHBvcnQvUUNfYnlfZ2Vub3R5cGUucG5nIiwgcGxvdCA9IFFDX2J5X2dlbm90eXBlLCBkZXZpY2UgPSAicG5nIiwgcGF0aCA9IE5VTEwsIHNjYWxlID0gMSwgd2lkdGggPSAxNSwgaGVpZ2h0ID0gMTAsIHVuaXRzID0gImNtIiwgZHBpID0gMzAwLCBsaW1pdHNpemUgPSBUUlVFKQogIApgYGAKCkludmVzdGlnYXRlIDIwIGFuZCAyIGZ1cnRoZXIKYGBge3J9CiMjIGhvdyBtYW55IHBsYXRlcz8KcGxhdGVfaW52ZXN0aWdhdGlvbiA8LSBwaGVub1t3aGljaChwaGVubyRzdWJfaWRlbnRpdHlfdXBkYXRlZCA9PSAiR0NTS08tMjAiIHwgcGhlbm8kc3ViX2lkZW50aXR5X3VwZGF0ZWQgPT0gIkdDU0tPLTIiIHwgcGhlbm8kc3ViX2lkZW50aXR5X3VwZGF0ZWQgPT0gIldULTIiIHwgcGhlbm8kc3ViX2lkZW50aXR5X3VwZGF0ZWQgPT0gIldULTIwIiksIF0KdGFibGUocGxhdGVfaW52ZXN0aWdhdGlvbiRwbGF0ZV9pZF91bmlxdWUpCmBgYAoKYWRkIGNvbHVtbnMgaWYgaXQgZmFpbGVkIFFDOgpgYGB7cn0KIyMgZ2V0IGNlbGxzIHRoYXQgYXJlIGZpbHRlcmVkIG91dApjZWxsc19rZXB0IDwtIHdoaWNoKHJvd25hbWVzKHBsYXRlX2ludmVzdGlnYXRpb24pICVpbiUgcm93bmFtZXMoc3MyX211dGFudHNfZmluYWxAbWV0YS5kYXRhKSkKCiMjIG1ha2UgZXh0cmEgY29sdW1uIGluIHBsb3R0aW5nIGRmCnBsYXRlX2ludmVzdGlnYXRpb24kY29sb3VyIDwtICJmaWx0ZXJlZF9vdXQiCnBsYXRlX2ludmVzdGlnYXRpb24kY29sb3VyW2NlbGxzX2tlcHRdIDwtICJwYXNzZWRfUUMiCgp0YWJsZShwbGF0ZV9pbnZlc3RpZ2F0aW9uJGNvbG91cikKYGBgCgpgYGB7cn0KIyMgYWRkIGNvbHMgZm9yIHBsb3R0aW5nCnBsYXRlX2ludmVzdGlnYXRpb24kUm93IDwtIGFzLm51bWVyaWMobWF0Y2godG91cHBlcihzdWJzdHIocGxhdGVfaW52ZXN0aWdhdGlvbiR3ZWxsX25hbWVfUiwgMSwgMSkpLCBMRVRURVJTKSkKcGxhdGVfaW52ZXN0aWdhdGlvbiRDb2x1bW4gPC0gYXMubnVtZXJpYyhzdWJzdHIocGxhdGVfaW52ZXN0aWdhdGlvbiR3ZWxsX25hbWVfUiwgMiwgNSkpCmBgYAoKcGxvdApgYGB7cn0KcGxhdGVfbmFtZXMgPC0gdW5pcXVlKHBsYXRlX2ludmVzdGlnYXRpb24kcGxhdGVfaWRfdW5pcXVlKQpwbG90X2xpc3QgPSBsaXN0KCkKCmZvcihpIGluIHNlcV9hbG9uZyhwbGF0ZV9uYW1lcykpewojIyBtYWtlIGRmCiAgdGFibGVfcGxhdGVtYXAgPC0gcGxhdGVfaW52ZXN0aWdhdGlvbltwbGF0ZV9pbnZlc3RpZ2F0aW9uJHBsYXRlX2lkX3VuaXF1ZSA9PSBwbGF0ZV9uYW1lc1tpXSwgXQogICMjIHBsb3QKICBwIDwtIGdncGxvdChkYXRhPXRhYmxlX3BsYXRlbWFwLCBhZXMoeD1Db2x1bW4sIHk9Um93KSkgKwogICNzZXQgdXAgdGhlIHBsYXRlbWFwIGxheW91dAogICAgICBnZW9tX3BvaW50KGRhdGE9ZXhwYW5kLmdyaWQoc2VxKDEsIDEyKSwgc2VxKDEsIDgpKSwgYWVzKHg9VmFyMSwgeT1WYXIyKSwgY29sb3I9ImdyZXk5MCIsIGZpbGw9IndoaXRlIiwgc2hhcGU9MjEsIHNpemU9NikgKwogICNDaGFuZ2UgdGhlIHNoYXBlIGFuZCBjb2xvdXIgb2YgcG9pbnRzIGZvciBhIHZhcmlhYmxlCiAgICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBjb2xvdXIpKSArCiAgI2NoYW5nZSB0aGUgY29sb3VycwogICAgI3NjYWxlX2NvbG91cl92aXJpZGlzX2MoZ3VpZGUgPSAiY29sb3VyYmFyIiwgbmEudmFsdWU9IndoaXRlIikgKwogICNmaXggdGhlIHJhdGlvIG9mIGNvb3JkaW5hdGVzCiAgICBjb29yZF9maXhlZChyYXRpbz0oMTMvMTIpLyg5LzgpLCB4bGltPWMoMC41LCAxMi41KSwgeWxpbT1jKDAuNSwgOC41KSkgKwogICNhZGQgbGFiZWxzIGZvciB0aGUgeSBheGlzCiAgICBzY2FsZV95X3JldmVyc2UoYnJlYWtzPXNlcSgxLCA4KSwgbGFiZWxzPUxFVFRFUlNbMTo4XSkgKwogICNhZGQgbGFiZWxzIGZvciB0aGUgeCBheGlzCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgxLCAxMikpICsKICAjQWRkIGEgdGl0bGUKICAgIGxhYnModGl0bGU9cGxhdGVfbmFtZXNbaV0gLCBzaXplID0gNiwgY29sb3VyID0gIlFDIFJlc3VsdCIpICsKICAjcm90YXRlIGxlZ2VuZCBndWlkZSBiZWNhdXNlIG90aGVyd2lzZSB5b3UgY2FuJ3Qgc2VlIG51bWJlcnM6CiAgICBndWlkZXMoZmlsbCA9IGd1aWRlX2NvbG9yYmFyKGJhcndpZHRoID0gMC41LCBiYXJoZWlnaHQgPSAxMCwgdGl0bGU9IlZhbHVlIiksIGNvbG91ciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemU9NCkpKSArCiAgI2NoYW5nZSB0aGUgY29sb3VycwogICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcz1jKCJyZWQyIiwgImdyZWVuNCIpKSArCiAgIyBtYWtlIG1pbW5pbXVtIHBvaW50IHNpemUgYmlnZ2VyCiAgICAjc2NhbGVfc2l6ZV9jb250aW51b3VzKHJhbmdlID0gYygyLDEwKSkgKwogICMgbWFrZSBpbnRvIGEgcGxhdGUgcGxvdAogICAgdGhlbWVfYmRjX21pY3JvdGl0ZXIoKSArCiAgIyBtYWtlIHRoZSBmb250IHNpemUgaW4gdGhlIGxlZ2VuZCBiaWdnZXIKICAgIHRoZW1lKGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTEwLCBjb2xvdXIgPSAiYmxhY2siKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEwKSkKCiMjIHByaW50CnBsb3RfbGlzdFtbaV1dIDwtIHAKfQoKZm9yIChpIGluIHNlcV9hbG9uZyhwbGF0ZV9uYW1lcykpIHsKICAgIHByaW50KHBsb3RfbGlzdFtbaV1dKQp9CmBgYAoKYGBge3J9CiMjIGxvYWQgdGhpcyBsaWJyYXJ5IHRvIHVzZSBncmlkLmFycmFuZ2UgZnVuY3Rpb24KbGlicmFyeShncmlkRXh0cmEpCgojIyB1c2UgdGhpcyBmdW5jdGlvbiB0byBleHRyYWN0IGxlZ2VuZDoKIyMgc291cmNlOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xMzY0OTQ3My9hZGQtYS1jb21tb24tbGVnZW5kLWZvci1jb21iaW5lZC1nZ3Bsb3RzCiMjIHNvdXJjZTogaHR0cHM6Ly9naXRodWIuY29tL2hhZGxleS9nZ3Bsb3QyL3dpa2kvU2hhcmUtYS1sZWdlbmQtYmV0d2Vlbi10d28tZ2dwbG90Mi1ncmFwaHMKZ19sZWdlbmQ8LWZ1bmN0aW9uKGEuZ3Bsb3QpewogICB0bXAgPC0gZ2dwbG90X2d0YWJsZShnZ3Bsb3RfYnVpbGQoYS5ncGxvdCkpCiAgIGxlZyA8LSB3aGljaChzYXBwbHkodG1wJGdyb2JzLCBmdW5jdGlvbih4KSB4JG5hbWUpID09ICJndWlkZS1ib3giKQogICBsZWdlbmQgPC0gdG1wJGdyb2JzW1tsZWddXQogICByZXR1cm4obGVnZW5kKX0KCiMjIGdldCBsZWdlbmQKbXlsZWdlbmQ8LWdfbGVnZW5kKHBsb3RfbGlzdFtbMV1dKQoKIyMgbWFrZSBhIGZpbmFsIHBsb3QKUUNfZmFpbGVkX3BsYXRlcyA8LSBncmlkLmFycmFuZ2UoYXJyYW5nZUdyb2IocGxvdF9saXN0W1sxXV0gKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiTXV0YW50IDIwIiwgIlxuIiwgInBsYXRlIDEiKSkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xpc3RbWzJdXSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJNdXRhbnQgMjAiLCAiXG4iLCAicGxhdGUgMiIpKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGlzdFtbM11dICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyBsYWJzKHRpdGxlID0gcGFzdGUoIk11dGFudCAyMCIsICJcbiIsICJwbGF0ZSAzIikpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9saXN0W1s0XV0gKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiTXV0YW50IDIwIiwgIlxuIiwgInBsYXRlIDQiKSkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xpc3RbWzVdXSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsgbGFicyh0aXRsZSA9IHBhc3RlKCJNdXRhbnQgMiIsICJcbiIsICJwbGF0ZSAxIikpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9saXN0W1s2XV0gKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIGxhYnModGl0bGUgPSBwYXN0ZSgiTXV0YW50IDIiLCAiXG4iLCAicGxhdGUgMiIpKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSwgbnJvdz0yKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG15bGVnZW5kLCBucm93PTIsaGVpZ2h0cz1jKDEwLDIpKQoKCgojIyBtYWtlIGFnZ3JlZ2F0ZSBwbG90CiMgUUNfZmFpbGVkX3BsYXRlcyA8LSAocGxvdF9saXN0W1sxXV0gKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiMgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGlzdFtbMl1dICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKwojICAgICAgICAgICAgICAgICAgICAgICBwbG90X2xpc3RbWzNdXSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpICsKIyAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9saXN0W1s0XV0gKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArCiMgICAgICAgICAgICAgICAgICAgICAgIHBsb3RfbGlzdFtbNV1dICsKIyAgICAgICAgICAgICAgICAgICAgICAgcGxvdF9saXN0W1s2XV0gKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQojICkKCiMjIHBsb3QKUUNfZmFpbGVkX3BsYXRlcwoKIyMgc2F2ZQpnZ3NhdmUoIi9Vc2Vycy9BbmR5L0dDU0tPL0dDU0tPX2FuYWx5c2lzX2dpdC9pbWFnZXNfdG9fZXhwb3J0L1FDX2ZhaWxlZF9wbGF0ZXMucG5nIiwgcGxvdCA9IFFDX2ZhaWxlZF9wbGF0ZXMsIGRldmljZSA9ICJwbmciLCBwYXRoID0gTlVMTCwgc2NhbGUgPSAxLCB3aWR0aCA9IDIyLCBoZWlnaHQgPSAxNywgdW5pdHMgPSAiY20iLCBkcGkgPSAzMDAsIGxpbWl0c2l6ZSA9IFRSVUUpCmBgYAoKIyMjIEFkZCBidWxrIG1ldGFkYXRhCgpBZGQgaW4gYnVsayBkYXRhIHByZWRpY3Rpb25zCgojIyMjIGhvbyBldCBhbC4KYGBge3IgaG9vfQojUGIgUHJlZGljdGlvbiBjb3JyZWxhdGlvbnMgd2l0aCBidWxrIGRhdGEgKGFzZXh1YWwgaG9vKTogCgojTG9hZCBpbiByZXF1aXJlZCBwYWNrYWdlOgpsaWJyYXJ5KEhtaXNjKQojQ29vZXJjZSBleHByZXNzaW9uIGRhdGEgaW50byBhIG1hdHJpeCBhbmQgbG9hZCBpbiB0aGUgcmVmZXJlbmNlIHRpbWVjb3Vyc2UgZGF0YToKeDEwIDwtIGFzLm1hdHJpeChzczJfbXV0YW50c19maW5hbEBhc3NheXMkUk5BQGRhdGEpCnJvd25hbWVzKHgxMCkgPC0gZ3N1YigiLSIsICJfIiwgcm93bmFtZXMoeDEwKSkKI3JlYWQgaW4gYnVsayBkYXRhOgpob288LWFzLm1hdHJpeChyZWFkLnRhYmxlKCJSZWZlcmVuY2VfYnVsa19kYXRhL2hvb19iZXJnMi50eHQiLGhlYWRlcj1ULCByb3cubmFtZXM9MSkpCiNNYWtlIGEgYmxhbmsgZGF0YWZyYW1lIGluIHdoaWNoIHRvIGFkZCBwcmVkaWN0aW9uOgpkZiA8LSBkYXRhLmZyYW1lKG1hdHJpeChuY29sID0gNCwgbnJvdyA9IDApKQpjb2xuYW1lcyhkZikgPC0gYygiUHJlZGljdGlvbihTcGVhcm1hbikiLCJyKFNwZWFybWFuKSIsIlByZWRpY3Rpb24oUGVhcnNvbnMpIiwicihQZWFyc29ucykiKQojRG8gY29ycmVsYXRpb25zIHdpdGggYnVsayBkYXRhIHVzaW5nIGJvdGggU3BlYXJtYW4gYW5kIFBlYXJzb24gKGFuZCB0aGUgdG9wIDEwMDAgZ2VuZXMpOgpmb3IgKGkgaW4gMTpuY29sKHgxMCkpCnsKICBzaGFyZWQ8LWludGVyc2VjdChyb3cubmFtZXMoYXMubWF0cml4KGhlYWQoc29ydCh4MTBbLGldLCBkZWNyZWFzaW5nPVRSVUUpLDEwMDApKSkscm93Lm5hbWVzKGhvbykpCiAgc3RlcDA8LXJjb3JyKHgxMFtzaGFyZWQsaV0saG9vW3NoYXJlZCwxOjEyXSx0eXBlID0gInNwZWFybWFuIikKICBzdGVwMTwtYXMubWF0cml4KHQoc3RlcDAkclsyOjEzLDFdKSkKICBzdGVwMjwtcmNvcnIoeDEwW3NoYXJlZCxpXSxob29bc2hhcmVkLDE6MTJdLHR5cGUgPSAicGVhcnNvbiIpCiAgc3RlcDM8LWFzLm1hdHJpeCh0KHN0ZXAyJHJbMjoxMywxXSkpCiAgc3RlcDQ8LWNiaW5kKGNvbG5hbWVzKHN0ZXAxKVt3aGljaC5tYXgoc3RlcDEpXSxzdGVwMVt3aGljaC5tYXgoc3RlcDEpXSxjb2xuYW1lcyhzdGVwMylbd2hpY2gubWF4KHN0ZXAzKV0sc3RlcDNbd2hpY2gubWF4KHN0ZXAzKV0pCiAgY29sbmFtZXMoc3RlcDQpIDwtIGMoIlByZWRpY3Rpb24oU3BlYXJtYW4pIiwicihTcGVhcm1hbikiLCJQcmVkaWN0aW9uKFBlYXJzb25zKSIsInIoUGVhcnNvbnMpIikKICByb3duYW1lcyhzdGVwNCk8LWNvbG5hbWVzKHgxMClbaV0KICBkZjwtcmJpbmQoZGYsc3RlcDQpCn0KI1dyaXRlIG91dCBkYXRhIGludG8gYSBjc3YgZmlsZToKI3dyaXRlLmNzdihkZnJpbmdyLGZpbGU9Ii9Vc2Vycy9hcjE5L0Rlc2t0b3AvUGhEL0FSMDRfR0NTS09fcHJvamVjdC9BbGxfbXV0YW50c19GZWJfMjAxOC9wcmVkaWN0aW9ucGJjb21iaW5lZC5jc3YiKQojQ2hhbmdlIHRoZSBmb3JtYXQgb2YgdGhlIG91dHB1dCB0byBtYWtlIGl0IG1vcmUgcmVhZGFibGU6CiNnc3ViKCJQYl8iLCIiLCBkZnJpbmdyWywxXSkgLSBNYWtlIHByZWRpY3Rpb25zIGludG8gMThoci5kYXQgZm9ybWF0OgoKI3NwZWFybWFuOgpkZlssMV0gPC0gZ3N1YigiUGJfIiwiIiwgZGZbLDFdKQojUmVtb3ZlIGhyLmRhdCBmcm9tIGxpc3Q6CmRmWywxXSA8LSBnc3ViKCJoci5kYXQiLCIiLCBkZlssMV0pCiNDaGVjayAtIGRmcmluZ3JbLDFdCiNNYWtlIGludG8gYSBudW1iZXI6CmRmWywxXSA8LSBhcy5udW1lcmljKGRmWywxXSkKZGZbLDJdIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGRmWywyXSkpCgojcGVhcnNvbjoKZGZbLDNdIDwtIGdzdWIoIlBiXyIsIiIsIGRmWywzXSkKI1JlbW92ZSBoci5kYXQgZnJvbSBsaXN0OgpkZlssM10gPC0gZ3N1YigiaHIuZGF0IiwiIiwgZGZbLDNdKQojQ2hlY2sgLSBkZnJpbmdyWywxXQojTWFrZSBpbnRvIGEgbnVtYmVyOgpkZlssM10gPC0gYXMubnVtZXJpYyhkZlssM10pCmRmWyw0XSA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihkZlssNF0pKQojYWRkIHRvIDEwWCBvYmplY3Q6CnNzMl9tdXRhbnRzX2ZpbmFsIDwtIEFkZE1ldGFEYXRhKHNzMl9tdXRhbnRzX2ZpbmFsLCBtZXRhZGF0YSA9IGRmKQpgYGAKCiMjIyMgS2FzaWEncyBkYXRhCkNhbiBhbHNvIGRvIHdpdGggS2FzaWEncyB0aW1lY291cnNlIGRhdGE6CmBgYHtyIGthc2lhfQprYXM8LWFzLm1hdHJpeChyZWFkLnRhYmxlKCJSZWZlcmVuY2VfYnVsa19kYXRhL0FQMk9FVEMudHh0IixoZWFkZXI9VCwgcm93Lm5hbWVzPTEpKQojTWFrZSBhIGJsYW5rIGRhdGFmcmFtZSBpbiB3aGljaCB0byBhZGQgcHJlZGljdGlvbjoKZGZzIDwtIGRhdGEuZnJhbWUobWF0cml4KG5jb2wgPSA0LCBucm93ID0gMCkpCmNvbG5hbWVzKGRmcykgPC0gYygiSUQiLCJQcmVkaWN0aW9uIiwiciAoUGVhcnNvbikiKQojRG8gY29ycmVsYXRpb25zIHdpdGggYnVsayBkYXRhIHVzaW5nIGJvdGggU3BlYXJtYW4gYW5kIFBlYXJzb24gKGFuZCB0aGUgdG9wIDEwMDAgZ2VuZXMpOgpmb3IgKGkgaW4gMTpuY29sKHgxMCkpCnsKICBzaGFyZWQ8LWludGVyc2VjdChyb3cubmFtZXMoYXMubWF0cml4KGhlYWQoc29ydCh4MTBbLGldLCBkZWNyZWFzaW5nPVRSVUUpLDEwMDApKSkscm93bmFtZXMoa2FzKSkKICBzdGVwMDwtcmNvcnIoeDEwW3NoYXJlZCxpXSxrYXNbc2hhcmVkLDE6MTBdLHR5cGUgPSAic3BlYXJtYW4iKQogIHN0ZXAxPC1hcy5tYXRyaXgodChzdGVwMCRyWzI6MTEsMV0pKQogIHN0ZXAyPC1yY29ycih4MTBbc2hhcmVkLGldLGthc1tzaGFyZWQsMToxMF0sdHlwZSA9ICJwZWFyc29uIikKICBzdGVwMzwtYXMubWF0cml4KHQoc3RlcDIkclsyOjExLDFdKSkKICBzdGVwNDwtY2JpbmQoY29sbmFtZXMoc3RlcDEpW3doaWNoLm1heChzdGVwMSldLHN0ZXAxW3doaWNoLm1heChzdGVwMSldLGNvbG5hbWVzKHN0ZXAzKVt3aGljaC5tYXgoc3RlcDMpXSxzdGVwM1t3aGljaC5tYXgoc3RlcDMpXSkKICBjb2xuYW1lcyhzdGVwNCkgPC0gYygiUHJlZGljdGlvbihTcGVhcm1hbikiLCJyKFNwZWFybWFuKSIsIlByZWRpY3Rpb24oUGVhcnNvbnMpIiwicihQZWFyc29ucykiKQogIHJvd25hbWVzKHN0ZXA0KTwtY29sbmFtZXMoeDEwKVtpXQogIGRmczwtcmJpbmQoZGZzLHN0ZXA0KQp9CiNXcml0ZSBvdXQgZGF0YSBpbnRvIGEgY3N2IGZpbGU6CiN3cml0ZS5jc3YoZGYsZmlsZT0iL1VzZXJzL2FyMTkvRGVza3RvcC9QaEQvQVIwNF9HQ1NLT19wcm9qZWN0L0FsbF9tdXRhbnRzX0ZlYl8yMDE4L3ByZWRpY3Rpb25rYXNpYWNvbWJpbmVkLmNzdiIpCgojQ2hhbmdlIHRoZSBmb3JtYXQgb2YgdGhlIG91dHB1dCB0byBtYWtlIGl0IG1vcmUgcmVhZGFibGU6CiNnc3ViKCJQYl8iLCIiLCBkZnNbLDFdKSAtIE1ha2UgcHJlZGljdGlvbnMgaW50byAxOGhyLmRhdCBmb3JtYXQ6CmRmc1ssMV0gPC0gZ3N1YigiWCIsIiIsIGRmc1ssMV0pCiNNYWtlIGludG8gYSBudW1iZXI6CmRmc1ssMV0gPC0gYXMubnVtZXJpYyhkZnNbLDFdKQojTWFrZSBpbnRvIGEgbnVtYmVyOgpkZnNbLDJdIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGRmc1ssMl0pKQoKI2dzdWIoIlBiXyIsIiIsIGRmc1ssMV0pIC0gTWFrZSBwcmVkaWN0aW9ucyBpbnRvIDE4aHIuZGF0IGZvcm1hdDoKZGZzWywzXSA8LSBnc3ViKCJYIiwiIiwgZGZzWywzXSkKI01ha2UgaW50byBhIG51bWJlcjoKZGZzWywzXSA8LSBhcy5udW1lcmljKGRmc1ssM10pCiNkZnNbLDFdCiNNYWtlIGludG8gYSBudW1iZXI6CmRmc1ssNF0gPC0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoZGZzWyw0XSkpCgpjb2xuYW1lcyhkZnMpIDwtIGMoJ1ByZWRpY3Rpb24oU3BlYXJtYW4pX0thc2lhJywgJ3IoU3BlYXJtYW4pX0thc2lhJywgJ1ByZWRpY3Rpb24oUGVhcnNvbilfS2FzaWEnLCAncihQZWFyc29uKV9LYXNpYScpCiNhZGQgdG8gU2V1cmF0OgojYWRkIHRvIDEwWCBvYmplY3Q6CnNzMl9tdXRhbnRzX2ZpbmFsIDwtIEFkZE1ldGFEYXRhKHNzMl9tdXRhbnRzX2ZpbmFsLCBkZnMpCmBgYAoKIyMjIE5vcm1hbGlzYXRpb24Kbm9ybWFsaXNlIGFuZCBmaW5kIHZhcmlhYmxlIGdlbmVzCmBgYHtyfQojIyBub3JtYWxpc2UKc3MyX211dGFudHNfZmluYWwgPC0gTm9ybWFsaXplRGF0YShzczJfbXV0YW50c19maW5hbCwgbm9ybWFsaXphdGlvbi5tZXRob2QgPSAiTG9nTm9ybWFsaXplIiwgc2NhbGUuZmFjdG9yID0gMTAwMDApCgojIyBmaW5kIHZhcmlhYmxlIGdlbmVzCnNzMl9tdXRhbnRzX2ZpbmFsIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKHNzMl9tdXRhbnRzX2ZpbmFsLCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDApCgojIyBtYWtlIGEgbGlzdCBvZiBhbGwgZ2VuZXMgaW4gdGhlIGRhdGFzZXQKYWxsLmdlbmVzIDwtIHJvd25hbWVzKHNzMl9tdXRhbnRzX2ZpbmFsKQoKIyMgc2NhbGUgZGF0YSBvbiBhbGwgZ2VuZXMKc3MyX211dGFudHNfZmluYWwgPC0gU2NhbGVEYXRhKHNzMl9tdXRhbnRzX2ZpbmFsLCBmZWF0dXJlcyA9IGFsbC5nZW5lcykKYGBgCgojIyMgRGltZW5zaW9uYWxpdHkgcmVkdWN0aW9uCgojIyMjIFBDQQpgYGB7cn0Kc3MyX211dGFudHNfZmluYWwgPC0gUnVuUENBKHNzMl9tdXRhbnRzX2ZpbmFsLCBmZWF0dXJlcyA9IFZhcmlhYmxlRmVhdHVyZXMob2JqZWN0ID0gc3MyX211dGFudHNfZmluYWwpLCB2ZXJib3NlID0gRkFMU0UpCmBgYAoKUENBIHBsb3QKYGBge3J9CkRpbVBsb3Qoc3MyX211dGFudHNfZmluYWwsIHJlZHVjdGlvbiA9ICJwY2EiKQpgYGAKCmBgYHtyfQpFbGJvd1Bsb3Qoc3MyX211dGFudHNfZmluYWwsIG5kaW1zID0gMzAsIHJlZHVjdGlvbiA9ICJwY2EiKQpgYGAKCiMjIyMgRmluZCBjbHVzdGVycwpgYGB7cn0Kc3MyX211dGFudHNfZmluYWwgPC0gRmluZE5laWdoYm9ycyhzczJfbXV0YW50c19maW5hbCwgZGltcyA9IDE6MjEpCnNzMl9tdXRhbnRzX2ZpbmFsIDwtIEZpbmRDbHVzdGVycyhzczJfbXV0YW50c19maW5hbCwgcmVzb2x1dGlvbiA9IDEpCmBgYAoKIyMjIyBVTUFQCmBgYHtyfQpzczJfbXV0YW50c19maW5hbCA8LVJ1blVNQVAoc3MyX211dGFudHNfZmluYWwsIHJlZHVjdGlvbiA9ICJwY2EiLCBkaW1zID0gMToxMCwgbi5uZWlnaGJvcnMgPSAxNTAsIHNlZWQudXNlID0gMTIzNCwgbWluLmRpc3QgPSAwLjQsIHJlcHVsc2lvbi5zdHJlbmd0aCA9IDAuMDMsIGxvY2FsLmNvbm5lY3Rpdml0eSA9IDE1MCkKRGltUGxvdChzczJfbXV0YW50c19maW5hbCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJpZGVudCIsIGxhYmVsID0gVFJVRSwgY29vcmQuZml4ZWQgPSBUUlVFKQpgYGAKCgoKYGBge3J9CiNzczJfbXV0YW50c19maW5hbCA8LSBSdW5VTUFQKHNzMl9tdXRhbnRzX2ZpbmFsLCBkaW1zID0gMToyMSkKYGBgCgpVTUFQIFBsb3RzCmBgYHtyfQojRGltUGxvdChzczJfbXV0YW50c19maW5hbCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJpZGVudCIsIGxhYmVsID0gVFJVRSwgY29vcmQuZml4ZWQgPSBUUlVFKQpgYGAKCmBgYHtyfQpEaW1QbG90KHNzMl9tdXRhbnRzX2ZpbmFsLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gImlkZW50aXR5X3VwZGF0ZWQiKQpgYGAKCiMjIyBDbHVzdGVyIGFzc2lnbm1lbnQKCiMjIyMgSW50ZXJhY3RpdmUKYGBge3J9CnBsb3QgPC0gRmVhdHVyZVBsb3Qoc3MyX211dGFudHNfZmluYWwsIGZlYXR1cmVzID0gIm5GZWF0dXJlX1JOQSIsIHJlZHVjdGlvbiA9ICJ1bWFwIikgICAKCkhvdmVyTG9jYXRvcihwbG90ID0gcGxvdCwgaW5mb3JtYXRpb24gPSBGZXRjaERhdGEoc3MyX211dGFudHNfZmluYWwsIHZhcnMgPSBjKCJuRmVhdHVyZV9STkEiLCAiaWRlbnQiLCAiaWRlbnRpdHlfdXBkYXRlZCIpKSkKYGBgCgojIyMjIG5nZW5lcywgbm1pdG8sIG5jb3VudHMgdmlzdWFsaXNhdGlvbgoKYGBge3J9CiMjIGFkZCBjb2x1bW4gdG8gbG9nIGNvdW50cyBzbyB0aGV5IGFyZSBlYXNpZXIgdG8gdmlzdWFsaXNlCnNzMl9tdXRhbnRzX2ZpbmFsIDwtIEFkZE1ldGFEYXRhKHNzMl9tdXRhbnRzX2ZpbmFsLCBsb2cxMChzczJfbXV0YW50c19maW5hbEBtZXRhLmRhdGEkbkNvdW50X1JOQSksIGNvbC5uYW1lID0gIm5Db3VudF9sb2cxMCIpCgpGZWF0dXJlUGxvdChzczJfbXV0YW50c19maW5hbCwgZmVhdHVyZXMgPSBjKCJuQ291bnRfUk5BIiwgIm5Db3VudF9sb2cxMCIsICJuRmVhdHVyZV9STkEiLCAicGVyY2VudC5tdCIpLCByZWR1Y3Rpb24gPSAidW1hcCIpICAgCmBgYAoKVmlvbGluIHBsb3RzIGNsdXN0ZXItYnktY2x1c3RlcjoKYGBge3J9ClZsblBsb3Qob2JqZWN0ID0gc3MyX211dGFudHNfZmluYWwsIGZlYXR1cmVzID0gIm5GZWF0dXJlX1JOQSIsIHB0LnNpemUgPSAwLjAxKSArCiAgbGFicyh4PSJDbHVzdGVyIiwKICAgICAgIHk9IkdlbmVzIHBlciBDZWxsIiwKICAgICAgIHRpdGxlID0gIk51bWJlciBvZiBHZW5lcyBwZXIgQ2VsbCIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpWbG5QbG90KG9iamVjdCA9IHNzMl9tdXRhbnRzX2ZpbmFsLCBmZWF0dXJlcyA9ICJuQ291bnRfbG9nMTAiLCBwdC5zaXplID0gMC4wMSkgKwogIGxhYnMoeD0iQ2x1c3RlciIsCiAgICAgICB5PSJMb2cxMChDb3VudHMgcGVyIENlbGwpIiwKICAgICAgIHRpdGxlID0gIk51bWJlciBvZiBDb3VudHMgcGVyIENlbGwiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKVmxuUGxvdChvYmplY3QgPSBzczJfbXV0YW50c19maW5hbCwgZmVhdHVyZXMgPSAicGVyY2VudC5tdCIsIHB0LnNpemUgPSAwLjAxKSArCiAgbGFicyh4PSJDbHVzdGVyIiwKICAgICAgIHk9IiUgTWl0b2Nob25kcmlhbCBSZWFkcyIsCiAgICAgICB0aXRsZSA9ICJQZXJjZW50YWdlIG9mIE1pdG9jaG9uZHJpYWwgUmVhZHMgcGVyIENlbGwiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCiMjIyMgRXhwcmVzc2lvbiBvZiBtYXJrZXIgZ2VuZXMKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gOH0KIyBQQkFOS0EtMDUxNTAwMCAtIHAyNSAtIGZlbWFsZQojIFBCQU5LQS0xMzE5NTAwIC0gQ0NQMiAtIGZlbWFsZSAtIHVzZWQgaW4gODIwIGxpbmUKIyBQQkFOS0EtMTIxMjYwMCAtIEhBUDIgLSBtYWxlCiMgUEJBTktBLTA2MDA2MDAgLSBORUszIC0gbWFsZQojIFBCQU5LQS0xMzE1NzAwIC0gUk9OMiAtIChhc2V4dWFscyBhbmQgc29tZSBtYWxlPykKIyAiUEJBTktBLTA0MTYxMDAiIC0gZHluZW5pbiBoZWF2eSBjaGFpbiAtIG1hbGUgLSB1c2VkIGluIDgyMCBsaW5lCiMgUEJBTktBLTE0Mzc1MDAgLSBBUDItRyAtIHNldXhhbCBjb21taXRtZW50IGdlbmUKIyBQQkFOS0EtMDgzMTAwMCAtIE1TUDEgLSBsYXRlIGFzZXh1YWwKIyBQQkFOS0EtMTEwMjIwMCAtIE1TUDggLSBlYXJseSBhc2V4dWFsIChmcm9tIEJvemRlY2ggcGFwZXIpCkZlYXR1cmVQbG90KHNzMl9tdXRhbnRzX2ZpbmFsLCBmZWF0dXJlcyA9IGMoIlBCQU5LQS0wNTE1MDAwIiwgIlBCQU5LQS0xMzE5NTAwIiwgIlBCQU5LQS0xMjEyNjAwIiwiUEJBTktBLTA2MDA2MDAiLCAiUEJBTktBLTEzMTU3MDAiLCAiUEJBTktBLTA0MTYxMDAiLCAiUEJBTktBLTE0Mzc1MDAiLCAiUEJBTktBLTA4MzEwMDAiLCAiUEJBTktBLTExMDIyMDAiKSwgY29vcmQuZml4ZWQgPSBUUlVFKQpgYGAKCiMjIyMgRG90cGxvdApgYGB7ciwgcHJlcCBmb3IgZG90cGxvdH0KZGZfbWV0YV9kYXRhIDwtIGFzLmRhdGEuZnJhbWUoc3MyX211dGFudHNfZmluYWxAbWV0YS5kYXRhKQoKZG90X3Bsb3RfZGYgPC0gYXMuZGF0YS5mcmFtZS5tYXRyaXgodGFibGUoZGZfbWV0YV9kYXRhJFJOQV9zbm5fcmVzLjEsIGRmX21ldGFfZGF0YSRpZGVudGl0eV91cGRhdGVkKSkKCmRvdF9wbG90X2RmX3BjIDwtIChhcy5kYXRhLmZyYW1lLm1hdHJpeChwcm9wLnRhYmxlKHRhYmxlKGRmX21ldGFfZGF0YSRSTkFfc25uX3Jlcy4xLCBkZl9tZXRhX2RhdGEkaWRlbnRpdHlfdXBkYXRlZCksIG1hcmdpbiA9IDIpKSAqIDEwMCkKCmRvdF9wbG90X2RmX3BjJGNsdXN0ZXIgPC0gcm93bmFtZXMoZG90X3Bsb3RfZGZfcGMpCmxpYnJhcnkoZHBseXIpCmRvdF9wbG90X2RmX3BjX211dGF0ZWQgPC0gbXV0YXRlKGRvdF9wbG90X2RmX3BjKQpsaWJyYXJ5KHJlc2hhcGUyKQpkb3RfcGxvdF9kZl9wY19tZWx0ZWQgPC0gbWVsdChkb3RfcGxvdF9kZl9wYywgdmFyaWFibGUubmFtZSA9ICJjbHVzdGVyIikKY29sbmFtZXMoZG90X3Bsb3RfZGZfcGNfbWVsdGVkKVsyXSA8LSAiaWRlbnRpdHkiCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQ9IDd9CmxpYnJhcnkoZ2dwbG90MikKICBwID0gZ2dwbG90KGRvdF9wbG90X2RmX3BjX21lbHRlZCwKICAgICAgICAgICAgIGFlcyh5ID0gZmFjdG9yKGNsdXN0ZXIpLAogICAgICAgICAgICAgICAgIHggPSBmYWN0b3IoaWRlbnRpdHkpKSkgKwogICAgICBnZW9tX3BvaW50KGFlcyhjb2xvdXI9dmFsdWUsIHNpemU9dmFsdWUpKSArIAogICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3c9ImJsdWUiLCBoaWdoPSJyZWQiLCBsaW1pdHM9YyggMSwgbWF4KGRvdF9wbG90X2RmX3BjX21lbHRlZCR2YWx1ZSkpLCBuYS52YWx1ZT0id2hpdGUiKSArCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICB0aGVtZShwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCkpCiAgcCA9IHAgKwogICAgICB5bGFiKCJDbHVzdGVyIikgKwogICAgICB4bGFiKCJJZGVudGl0eSIpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTIsIGZhY2U9Iml0YWxpYyIsIGFuZ2xlPTQ1LCBoanVzdD0xKSkgKyAKICAgICAgdGhlbWUoYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9MTIsIGZhY2U9Iml0YWxpYyIpKQogIHByaW50KHApCmBgYAoKIyMjIyBleHByZXNzaW9uIG9mIDgyMCBtYXJrZXJzCgpgYGB7ciwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDEwfQpwbG90cyA8LSBGZWF0dXJlUGxvdChzczJfbXV0YW50c19maW5hbCwgZmVhdHVyZXMgPSBjKCJQQkFOS0EtMTMxOTUwMCIsICJQQkFOS0EtMDQxNjEwMCIpLCBibGVuZCA9IFRSVUUsIGNvbWJpbmUgPSBGQUxTRSwgY29vcmQuZml4ZWQgPSBUUlVFKQoKcGxvdHNbWzNdXSArIE5vTGVnZW5kKCkgICMgR2V0IGp1c3QgdGhlIGNvLWV4cHJlc3Npb24gcGxvdCwgYnVpbHQtaW4gbGVnZW5kIGlzIG1lYW5pbmdsZXNzIGZvciB0aGlzIHBsb3QKcGxvdHNbWzRdXSAjIEdldCBqdXN0IHRoZSBrZXkKQ29tYmluZVBsb3RzKHBsb3RzWzM6NF0sIGxlZ2VuZCA9ICdub25lJykgIyBTdGl0Y2ggdGhlIGNvLWV4cHJlc3Npb24gYW5kIGtleSBwbG90cyB0b2dldGhlcgpgYGAKCmlkZW50aWZ5IHdoaWNoIGNsdXN0ZXIgaXMgd2hpY2ggCmBgYHtyfQojIFBCQU5LQS0xMzE5NTAwIC0gQ0NQMiAtIGZlbWFsZSAtIHVzZWQgaW4gODIwIGxpbmUKIyBQQkFOS0EtMDQxNjEwMCAtIGR5bmVuaW4gaGVhdnkgY2hhaW4gLSBtYWxlIC0gdXNlZCBpbiA4MjAgbGluZQojIFBCQU5LQS0wODMxMDAwIC0gTVNQMSAtIGxhdGUgYXNleHVhbAojIFBCQU5LQS0xMTAyMjAwIC0gTVNQOCAtIGVhcmx5IGFzZXh1YWwgKGZyb20gQm96ZGVjaCBwYXBlcikKRG90UGxvdChzczJfbXV0YW50c19maW5hbCwgZmVhdHVyZXMgPSBjKCJQQkFOS0EtMTMxOTUwMCIsICJQQkFOS0EtMDQxNjEwMCIsICJQQkFOS0EtMDgzMTAwMCIsICJQQkFOS0EtMTEwMjIwMCIpKQoKIyAxOCAtIGFzZXggZWFybHkgLSAxCiMgMTcgLSBmZW1hbGUKIyAxNiAtIGZlbWFsZQojIDE1IC0gbWFsZQojIDE0IC0gZmVtYWxlICh3aXRoIHNvbWUgbGF0ZSBhc2V4PykKIyAxMyAtIG1hbGUKIyAxMiAtIGFzZXggZWFybHkgLSAzCiMgMTEgLSBtYWxlCiMgMTAgLSBhc2V4IGVhcmx5IC0gMAojIDkgLSBERVYgYnJhbmNoCiMgOCAtIGFzZXggbGF0ZSAtIDAKIyA3IC0gZmVtYWxlCiMgNiAtIGFzZXggbGF0ZSAtIDEKIyA1IC0gYXNleCBsYXRlIC0gMgojIDQgLSBERVYgYnJhbmNoCiMgMyAtIGFzZXggZWFybHkgLSAyCiMgMiAtIGFzZXggbGF0ZSAtIDMKIyAxIC0gbWFsZQojIDAgLSBmZW1hbGUKYGBgCgpgYGB7ciwgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodD0gN30KIyMgY2hhbmdlIHRoZSBsZXZlbHMgaW4gdGhlIG1ldGEgZGF0YQpzczJfbXV0YW50c19maW5hbEBtZXRhLmRhdGEkc2V1cmF0X2NsdXN0ZXJzX3Bsb3R0aW5nIDwtIHNzMl9tdXRhbnRzX2ZpbmFsQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMKCiMjIHJlb3JkZXIgdGhlIGxldmVscyBzbyB5b3UgY2FuIHBsb3QgdGhlIGNsdXRlcnMgYXMgeW91IHdpc2gKCiMgRGVmaW5lIG9yZGVyIG9mIGFwcGVhcmFuY2Ugb2YgdGltZXBvaW50cwpteV9sZXZlbHMgPC0gYygiMCIsICI2IiwgIjEyIiwgIjE0IiwgIjE2IiwgIjEiLCAiMTAiLCAiMTMiLCAiMTUiLCIzIiwgIjgiLCI3IiwgIjUiLCAiMiIsICI5IiwgIjE3IiwgIjQiLCAiMTEiKQoKIyBSZWxldmVsIG9iamVjdEB0aW1lcG9pbnQKc3MyX211dGFudHNfZmluYWxAbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVyc19wbG90dGluZyA8LSBmYWN0b3IoeCA9IHNzMl9tdXRhbnRzX2ZpbmFsQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnNfcGxvdHRpbmcsIGxldmVscyA9IG15X2xldmVscykKCkRvdFBsb3Qoc3MyX211dGFudHNfZmluYWwsIGZlYXR1cmVzID0gYygiUEJBTktBLTEzMTk1MDAiLCAiUEJBTktBLTA0MTYxMDAiLCAiUEJBTktBLTA4MzEwMDAiLCAiUEJBTktBLTExMDIyMDAiKSwgZ3JvdXAuYnkgPSAic2V1cmF0X2NsdXN0ZXJzX3Bsb3R0aW5nIikgKyB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkKYGBgCgpDb25maXJtIGxpZmUgY3ljbGUgZGVzaWduYXRpb25zOgoKYGBge3J9CkZlYXR1cmVQbG90KHNzMl9tdXRhbnRzX2ZpbmFsLCBmZWF0dXJlcyA9IGMoIlByZWRpY3Rpb24oU3BlYXJtYW4pX0thc2lhIiwgIlByZWRpY3Rpb24oU3BlYXJtYW4pIikpCmBgYAoKCgoKCgojIyMKIyBEdXJpbmcgY2hlY2ssIGp1c3QgcmFuIHRvIGhlcmUKIyMjCgoKCgoKCgoKCgpJbXByb3ZlIFVNQVAKYGBge3J9CnNzMl9tdXRhbnRzX2ZpbmFsIDwtIFJ1blVNQVAoc3MyX211dGFudHNfZmluYWwsIGRpbXMgPSAxOjEyLCByZWR1Y3Rpb24ubmFtZSA9ICJ1bWFwX2ltcHJvdmVkIikKYGBgCgpgYGB7cn0KRGltUGxvdChzczJfbXV0YW50c19maW5hbCwgcmVkdWN0aW9uID0gInVtYXBfaW1wcm92ZWQiLCBncm91cC5ieSA9ICJpZGVudCIsIGxhYmVsID0gVFJVRSwgY29vcmQuZml4ZWQgPSBUUlVFKQpgYGAKCgoKKioqCiMgNC4gQ2x1c3RlciB0b2dldGhlciB3aXRoIE1DQSBkYXRhIHsudGFic2V0fQoKIyMgUHJlcGFyZQoKIyMjIHNldCB1cCBNQ0EgZGF0YQpgYGB7cn0KIyMgcmVhZCBpbiBkYXRhCmNvdW50c19tY2EgPC0gcmVhZC50YWJsZSgiTUNBL2FsbGNvdW50czQuY3N2IiwgaGVhZGVyID0gVFJVRSwgc2VwID0gIiwiLCByb3cubmFtZXM9MSwgc3RyaW5nc0FzRmFjdG9ycyA9IFRSVUUpCmRpbShjb3VudHNfbWNhKQoKYW5ub19tY2EgPC0gcmVhZC5kZWxpbSgiTUNBL2FsbHBoZW5vOC4yLmNzdiIsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICIsIiwgcm93Lm5hbWVzPTEpCmRpbShhbm5vX21jYSkKCiMjIHN1YnNldCBhbGwgYmxvb2Qgc3RhZ2UgY2VsbHMKIyMgZmluZCBibG9vZCBzdGFnZXMKYmxvb2Rfc3RhZ2VzIDwtIGMoIk1lcm96b2l0ZSIsICJTaHoiLCAiTWFsZSIsICJTY2hpem9udCIsICJGZW1hbGUiLCAiVHJvcGhvem9pdGUiLCAiUmluZyIpCgpibG9vZF9zdGFnZV9jZWxsX25hbWVzIDwtIHJvd25hbWVzKGFubm9fbWNhW2Fubm9fbWNhJFNob3J0ZW5lZExpZmVTdGFnZTIgJWluJSBibG9vZF9zdGFnZXMsIF0pCgojIyBzdWJzZXQgZGF0YWZyYW1lcwpjb3VudHNfbWNhX2Jsb29kX3N0YWdlIDwtIGNvdW50c19tY2FbICxjb2xuYW1lcyhjb3VudHNfbWNhKSAlaW4lIGJsb29kX3N0YWdlX2NlbGxfbmFtZXNdCmRpbShjb3VudHNfbWNhX2Jsb29kX3N0YWdlKQoKYW5ub19tY2FfYmxvb2Rfc3RhZ2UgPC0gYW5ub19tY2Fbcm93bmFtZXMoYW5ub19tY2EpICVpbiUgYmxvb2Rfc3RhZ2VfY2VsbF9uYW1lcywgXQpkaW0oYW5ub19tY2FfYmxvb2Rfc3RhZ2UpCgojIyByZW1vdmUgY29udHJvbCBjZWxsczoKbm9uX2NvbnRyb2xfY2VsbF9uYW1lcyA8LSByb3duYW1lcyhhbm5vX21jYV9ibG9vZF9zdGFnZVthbm5vX21jYV9ibG9vZF9zdGFnZSROdW1iZXJfb2ZfY2VsbHMgPT0gMSwgXSkKY291bnRzX21jYV9ibG9vZF9zdGFnZSA8LSBjb3VudHNfbWNhX2Jsb29kX3N0YWdlWyAsY29sbmFtZXMoY291bnRzX21jYV9ibG9vZF9zdGFnZSkgJWluJSBub25fY29udHJvbF9jZWxsX25hbWVzXQpkaW0oY291bnRzX21jYV9ibG9vZF9zdGFnZSkKCmFubm9fbWNhX2Jsb29kX3N0YWdlIDwtIGFubm9fbWNhX2Jsb29kX3N0YWdlW3Jvd25hbWVzKGFubm9fbWNhX2Jsb29kX3N0YWdlKSAlaW4lIG5vbl9jb250cm9sX2NlbGxfbmFtZXMsIF0KZGltKGFubm9fbWNhX2Jsb29kX3N0YWdlKQoKIyMgY2hlY2sKaWRlbnRpY2FsKHJvd25hbWVzKGNvdW50c19tY2FfYmxvb2Rfc3RhZ2UpLCByb3duYW1lcyhjb3VudHMpKQpgYGAKCiMjIyBzZXQgdXAgTUNBIG9iamVjdAoKbWNhIG9iamVjdApgYGB7cn0KIyMgbWFrZSBTZXVyYXQgb2JqZWN0IHdpdGggc2FtZSBmaWx0ZXJpbmcgYXMgbWFpbiBvYmplY3QgYmVjYXVzZSB0aGV5IGFyZSBzZXF1ZW5jZWQgdG8gc2FtZSBkZXB0aDoKR0NTS09fbWNhIDwtIENyZWF0ZVNldXJhdE9iamVjdChjb3VudHMgPSBjb3VudHNfbWNhX2Jsb29kX3N0YWdlLCBtZXRhLmRhdGEgPSBhbm5vX21jYV9ibG9vZF9zdGFnZSwgbWluLmNlbGxzID0gMCwgbWluLmZlYXR1cmVzID0gMTIwLCBwcm9qZWN0ID0gIkdDU0tPIikKCkdDU0tPX21jYQoKR0NTS09fbWNhQG1ldGEuZGF0YSRleHBlcmltZW50IDwtICJtY2EiCnNzMl9tdXRhbnRzX2ZpbmFsQG1ldGEuZGF0YSRleHBlcmltZW50IDwtICJzczJfbXV0YW50cyIKYGBgCm4uYi4gYSBmaWx0ZXIgb2YgNDAgYWxsb3dzIHRoZSBtZXJvem9pdGVzIHRvIGNvbXBsZXRlIHRoZSByaW5nIGluIHRoZSBhc2V4dWFscwoKYGBge3J9ClZsblBsb3Qob2JqZWN0ID0gR0NTS09fbWNhLCBmZWF0dXJlcyA9ICJuRmVhdHVyZV9STkEiLCBwdC5zaXplID0gMC4wMSkgKwogIGxhYnMoeD0iQ2x1c3RlciIsCiAgICAgICB5PSJHZW5lcyBwZXIgQ2VsbCIsCiAgICAgICB0aXRsZSA9ICJOdW1iZXIgb2YgR2VuZXMgcGVyIENlbGwiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIGdlb21faGxpbmUoeWludGVyY2VwdD0yMjApCgpWbG5QbG90KG9iamVjdCA9IEdDU0tPX21jYSwgZmVhdHVyZXMgPSAibkNvdW50X1JOQSIsIHB0LnNpemUgPSAwLjAxKSArCiAgbGFicyh4PSJDbHVzdGVyIiwKICAgICAgIHk9IkxvZzEwKENvdW50cyBwZXIgQ2VsbCkiLAogICAgICAgdGl0bGUgPSAiTnVtYmVyIG9mIENvdW50cyBwZXIgQ2VsbCIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKIyMjIG5vcm1hbGlzZSBvYmplY3QKYGBge3J9CiMjIG5vcm1hbGlzZQpHQ1NLT19tY2EgPC0gTm9ybWFsaXplRGF0YShHQ1NLT19tY2EsIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIkxvZ05vcm1hbGl6ZSIsIHNjYWxlLmZhY3RvciA9IDEwMDAwKQojIyBmaW5kIHZhcmlhYmxlIGdlbmVzCkdDU0tPX21jYSA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhHQ1NLT19tY2EsIHNlbGVjdGlvbi5tZXRob2QgPSAidnN0IiwgbmZlYXR1cmVzID0gMjAwMCkKIyMgbWFrZSBhIGxpc3Qgb2YgYWxsIGdlbmVzIGluIHRoZSBkYXRhc2V0CmFsbC5nZW5lcyA8LSByb3duYW1lcyhHQ1NLT19tY2EpCiMjIHNjYWxlIGRhdGEgb24gYWxsIGdlbmVzCkdDU0tPX21jYSA8LSBTY2FsZURhdGEoR0NTS09fbWNhLCBmZWF0dXJlcyA9IGFsbC5nZW5lcykKYGBgCgojIyBJbnRlZ3JhdGUKCmBgYHtyfQojIyBtYWtlIGxpc3QKc3MyLm1jYS5saXN0IDwtIGxpc3QoR0NTS09fbWNhLCBzczJfbXV0YW50c19maW5hbCkKc3MyLm1jYS5hbmNob3JzIDwtIEZpbmRJbnRlZ3JhdGlvbkFuY2hvcnMob2JqZWN0Lmxpc3QgPSBzczIubWNhLmxpc3QsIGRpbXMgPSAxOjIxLCB2ZXJib3NlID0gRkFMU0UpCnNzMi5tY2EuaW50ZWdyYXRlZCA8LSBJbnRlZ3JhdGVEYXRhKGFuY2hvcnNldCA9IHNzMi5tY2EuYW5jaG9ycywgZGltcyA9IDE6MjEsIHZlcmJvc2UgPSBGQUxTRSwgZmVhdHVyZXMudG8uaW50ZWdyYXRlID0gYWxsLmdlbmVzKQpgYGAKCiMjIEFuYWx5c2UKClNjYWxlIGFuZCBQQ0EKYGBge3J9CiMgc2V0IGR1cmluZyBJbnRlZ3JhdGVEYXRhCkRlZmF1bHRBc3NheShzczIubWNhLmludGVncmF0ZWQpIDwtICJpbnRlZ3JhdGVkIgojIFJ1biB0aGUgc3RhbmRhcmQgd29ya2Zsb3cgZm9yIHZpc3VhbGl6YXRpb24gYW5kIGNsdXN0ZXJpbmcKc3MyLm1jYS5pbnRlZ3JhdGVkIDwtIFNjYWxlRGF0YShzczIubWNhLmludGVncmF0ZWQsIHZlcmJvc2UgPSBGQUxTRSkKc3MyLm1jYS5pbnRlZ3JhdGVkIDwtIFJ1blBDQShzczIubWNhLmludGVncmF0ZWQsIG5wY3MgPSAzMCwgdmVyYm9zZSA9IEZBTFNFKQpgYGAKCkluc3BlY3QgUENTOgpgYGB7cn0KRWxib3dQbG90KHNzMi5tY2EuaW50ZWdyYXRlZCwgbmRpbXMgPSAzMCwgcmVkdWN0aW9uID0gInBjYSIpCmBgYAoKVU1BUApgYGB7cn0Kc3MyLm1jYS5pbnRlZ3JhdGVkIDwtIFJ1blVNQVAoc3MyLm1jYS5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MjEpCmBgYAoKVU1BUCBwbG90OgpgYGB7cn0KI25hbWVzKHRlbngubWNhLmludGVncmF0ZWRAbWV0YS5kYXRhKVs5XSA8LSAiUHJlZGljdGlvbl9TcGVhcm1hbiIKcDEgPC0gRGltUGxvdChzczIubWNhLmludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAiZXhwZXJpbWVudCIsIHB0LnNpemUgPSAwLjAxKSArIGNvb3JkX2ZpeGVkKCkKcDIgPC0gRGltUGxvdChzczIubWNhLmludGVncmF0ZWQsIHJlZHVjdGlvbiA9ICJ1bWFwIiwgZ3JvdXAuYnkgPSAiU2hvcnRlbmVkTGlmZVN0YWdlMiIsIGxhYmVsID0gVFJVRSwgcmVwZWwgPSBUUlVFLCBwdC5zaXplID0gMC4wMSkgKyBjb29yZF9maXhlZCgpCnAzIDwtIERpbVBsb3Qoc3MyLm1jYS5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gIlJOQV9zbm5fcmVzLjEiLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMDEpICsgY29vcmRfZml4ZWQoKQpwMSArIHAyCmBgYAoKYGBge3J9CnAzCmBgYAoKIyMjIFVNQVAgb3B0aW1pc2F0aW9uCgp0cnkgdG8gbWFrZSBhIGJldHRlciBVTUFQOgpgYGB7cn0KZm9yKGkgaW4gYygyMCwyMDAsNDAwLDgwMCwxMjAwKSl7CnNzMi5tY2EuaW50ZWdyYXRlZCA8LSBSdW5VTUFQKHNzMi5tY2EuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjIxLCBzZWVkLnVzZSA9IGkpCgphc3NpZ24ocGFzdGUwKCJVTUFQXyIsIGkpICxEaW1QbG90KHNzMi5tY2EuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJSTkFfc25uX3Jlcy4xIiwgbGFiZWwgPSBUUlVFLCByZXBlbCA9IFRSVUUsIHB0LnNpemUgPSAwLjAxKSArIGNvb3JkX2ZpeGVkKCkpCn0KYGBgCgpgYGB7cn0KVU1BUF8yMApVTUFQXzIwMApVTUFQXzQwMApVTUFQXzgwMApVTUFQXzEyMDAKYGBgCgpgYGB7cn0KI3NzMi5tY2EuaW50ZWdyYXRlZCA8LSBSdW5VTUFQKHNzMi5tY2EuaW50ZWdyYXRlZCwgcmVkdWN0aW9uID0gInBjYSIsIGRpbXMgPSAxOjIxLCBzZWVkLnVzZSA9IDgwMCkKYGBgCgpgYGB7cn0Kc3MyLm1jYS5pbnRlZ3JhdGVkIDwtIFJ1blVNQVAoc3MyLm1jYS5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAicGNhIiwgZGltcyA9IDE6MTUpCmBgYAoKYGBge3J9CkRpbVBsb3Qoc3MyLm1jYS5pbnRlZ3JhdGVkLCByZWR1Y3Rpb24gPSAidW1hcCIsIGdyb3VwLmJ5ID0gIlJOQV9zbm5fcmVzLjEiLCBsYWJlbCA9IFRSVUUsIHJlcGVsID0gVFJVRSwgcHQuc2l6ZSA9IDAuMDEpICsgY29vcmRfZml4ZWQoKQpgYGAKCmBgYHtyfQpWbG5QbG90KG9iamVjdCA9IHNzMi5tY2EuaW50ZWdyYXRlZCwgZmVhdHVyZXMgPSAibkZlYXR1cmVfUk5BIiwgcHQuc2l6ZSA9IDAuMDEpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTEwMCkKYGBgCgpwbG90OgpgYGB7ciwgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDEwfQpwMSA8LSBEaW1QbG90KHNzMi5tY2EuaW50ZWdyYXRlZCwgcHQuc2l6ZSA9IDAuMDEsIGxhYmVsID0gVFJVRSkKcDIgPC0gRGltUGxvdChzczIubWNhLmludGVncmF0ZWQsIHB0LnNpemUgPSAwLjAxLCBncm91cC5ieSA9ICJTaG9ydGVuZWRMaWZlU3RhZ2UyIiwgbGFiZWwgPSBUUlVFKQpwMSArIHAyCmBgYAoKYGBge3J9CiMjIGFkZCBuZXcgY29sdW1uIApzczIubWNhLmludGVncmF0ZWRAbWV0YS5kYXRhJGNsdXN0ZXJzX2ludGVncmF0ZWQgPC0gc3MyLm1jYS5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMKCnNzMi5tY2EuaW50ZWdyYXRlZEBtZXRhLmRhdGEkY2x1c3RlcnNfaW50ZWdyYXRlZCA8LSBpZmVsc2UoaXMubmEoc3MyLm1jYS5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRjbHVzdGVyc19pbnRlZ3JhdGVkKSwgc3MyLm1jYS5pbnRlZ3JhdGVkQG1ldGEuZGF0YSRTaG9ydGVuZWRMaWZlU3RhZ2UyLCBzczIubWNhLmludGVncmF0ZWRAbWV0YS5kYXRhJGNsdXN0ZXJzX2ludGVncmF0ZWQpCgpEaW1QbG90KHNzMi5tY2EuaW50ZWdyYXRlZCwgcHQuc2l6ZSA9IDAuMDEsIGxhYmVsID0gVFJVRSwgc3BsaXQuYnkgPSAiZXhwZXJpbWVudCIsIGdyb3VwLmJ5ID0gImNsdXN0ZXJzX2ludGVncmF0ZWQiKSArIGNvb3JkX2ZpeGVkKCkgKyB0aGVtZV92b2lkKCkKYGBgCgpgYGB7ciwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDEwfQpwbG90cyA8LSBGZWF0dXJlUGxvdChzczIubWNhLmludGVncmF0ZWQsIGZlYXR1cmVzID0gYygiUEJBTktBLTEzMTk1MDAiLCAiUEJBTktBLTA0MTYxMDAiKSwgYmxlbmQgPSBUUlVFLCBjb21iaW5lID0gRkFMU0UsIGNvb3JkLmZpeGVkID0gVFJVRSwgc3BsaXQuYnkgPSAiZXhwZXJpbWVudCIpCgpwbG90c1tbN11dICsgTm9MZWdlbmQoKSAgIyBHZXQganVzdCB0aGUgY28tZXhwcmVzc2lvbiBwbG90LCBidWlsdC1pbiBsZWdlbmQgaXMgbWVhbmluZ2xlc3MgZm9yIHRoaXMgcGxvdApwbG90c1tbOF1dICMgR2V0IGp1c3QgdGhlIGtleQpDb21iaW5lUGxvdHMocGxvdHNbMzo0XSwgbGVnZW5kID0gJ25vbmUnLCBuY29sID0yLCBucm93ID0gMSwgcmVsX3dpZHRocyA9IGMoMiwgMSksIHJlbF9oZWlnaHRzID0gYyg0LDEpKSAjIFN0aXRjaCB0aGUgY28tZXhwcmVzc2lvbiBhbmQga2V5IHBsb3RzIHRvZ2V0aGVyCmBgYAoKIyMgY2x1c3RlcgoKZ2VuZXJhdGUgY2x1c3RlcnM6CmBgYHtyfQojIyBjb3B5IG9sZCBjbHVzdGVycwpzczIubWNhLmludGVncmF0ZWQgPC0gQWRkTWV0YURhdGEoc3MyLm1jYS5pbnRlZ3JhdGVkLCBzczIubWNhLmludGVncmF0ZWRAbWV0YS5kYXRhJFJOQV9zbm5fcmVzLjEsIGNvbC5uYW1lID0gInByZV9pbnRlZ3JhdGlvbl9jbHVzdGVycyIpCgojIyBnZW5lcmF0ZSBuZXcgY2x1c3RlcnMKI3NzMi5tY2EuaW50ZWdyYXRlZCA8LSBGaW5kTmVpZ2hib3JzKHNzMi5tY2EuaW50ZWdyYXRlZCwgZGltcyA9IDE6MjEpCiNzczIubWNhLmludGVncmF0ZWQgPC0gRmluZENsdXN0ZXJzKHNzMi5tY2EuaW50ZWdyYXRlZCwgcmVzb2x1dGlvbiA9IDEsIHJhbmRvbS5zZWVkID0gNDIsIGFsZ29yaXRobSA9IDIpCmBgYAoKIyMjIFNleCByYXRpbyBwbG90cwoKQ2FsY3VsYXRlIHNleCByYXRpb3MKYGBge3J9CiMjIHRoaXMgd2lsbCBvbmx5IHN1YnNldCBTUzIgY2VsbHMgYXMgdGhlc2UgYXJlIHRoZSBvbmx5IG9uZXMgd2l0aCBpZGVudGl0aWVzCgojIyBzdWJzZXQgbWFsZXMKc3MyX211dGFudHNfZmluYWxfbWFsZSA8LSBTdWJzZXREYXRhKHNzMl9tdXRhbnRzX2ZpbmFsLCBpZGVudC51c2UgPSBjKDEsMTAsMTMsMTYpKQoKIyMgc3Vic2V0IGZlbWFsZXMKc3MyX211dGFudHNfZmluYWxfZmVtYWxlIDwtIFN1YnNldERhdGEoc3MyX211dGFudHNfZmluYWwsIGlkZW50LnVzZSA9IGMoMCw5LDExLDE0LDE1LDUpKQoKIyMgaW5zcGVjdApzczJfbXV0YW50c19maW5hbF9tYWxlCnNzMl9tdXRhbnRzX2ZpbmFsX2ZlbWFsZQpgYGAKCmBgYHtyfQojIyBjYWxjdWxhdGUgc2V4IHJhdGlvcwojI3N1YnNldCBvdXQgSCsgc29ydGVkIGNlbGxzOgpkZl9tYWxlIDwtIHNzMl9tdXRhbnRzX2ZpbmFsX21hbGVAbWV0YS5kYXRhW3NzMl9tdXRhbnRzX2ZpbmFsX21hbGVAbWV0YS5kYXRhJGV4Y2x1ZGVfZm9yX3NleF9yYXRpbyA9PSBGQUxTRSxdCgpkaW0oZGZfbWFsZSkKCmRmX2ZlbWFsZSA8LSBzczJfbXV0YW50c19maW5hbF9mZW1hbGVAbWV0YS5kYXRhW3NzMl9tdXRhbnRzX2ZpbmFsX2ZlbWFsZUBtZXRhLmRhdGEkZXhjbHVkZV9mb3Jfc2V4X3JhdGlvID09IEZBTFNFLF0KCmRpbShkZl9mZW1hbGUpCgojIyBtYWtlIGRhdGFmcmFtZQpkZl9zZXhfcmF0aW8gPC0gbWVyZ2UoCiAgYXMuZGF0YS5mcmFtZSh0YWJsZShkZl9tYWxlJHN1Yl9pZGVudGl0eV91cGRhdGVkKSksIAogIGFzLmRhdGEuZnJhbWUodGFibGUoZGZfZmVtYWxlJHN1Yl9pZGVudGl0eV91cGRhdGVkKSksIAogIGJ5ID0gIlZhcjEiLCBhbGw9VFJVRSkKCiMgb3IgdXNlIGlkZW50aXR5X3VwZGF0ZWQKCiMjIGFkZCBuYW1lcwpuYW1lcyhkZl9zZXhfcmF0aW8pIDwtIGMoImdlbm90eXBlIiwgIm1hbGUiLCAiZmVtYWxlIikKCiMjIGNoYW5nZSB0aGUgTkFzIHRvIDAKZGZfc2V4X3JhdGlvW2lzLm5hKGRmX3NleF9yYXRpbyldIDwtIDAKCiMjIGNhbGN1bGF0ZSBzZXggcmF0aW8KZGZfc2V4X3JhdGlvJHNleF9yYXRpbyA8LSAoZGZfc2V4X3JhdGlvJG1hbGUgKyAxKS8oZGZfc2V4X3JhdGlvJGZlbWFsZSkKCiMjIGxvZyBzZXggcmF0aW8KZGZfc2V4X3JhdGlvJHNleF9yYXRpb19sb2cgPC0gbG9nMTAoZGZfc2V4X3JhdGlvJHNleF9yYXRpbykKCiMjdmlldwpkZl9zZXhfcmF0aW8KYGBgCgpwbG90CmBgYHtyfQojIyByZW9yZGVyIGdlbm90eXBlIHNvIGl0IGlzIGluIHRoZSBjb3JyZWN0IG9yZGVyIGZvciBwbG90dGluZwojZGZfc2V4X3JhdGlvJGdlbm90eXBlIDwtIGZhY3RvcihkZl9zZXhfcmF0aW8kZ2Vub3R5cGUsIGxldmVscyA9IGMoIkdDU0tPLTIiLCAiR0NTS08tMyIsICJXVC0zIiwgIkdDU0tPLTEwXzgyMCIsICJHQ1NLTy0xMyIsICJXVC0xMyIsICJHQ1NLTy0xNyIsICJXVC0xNyIsICJHQ1NLTy0xOSIsICJXVC0xOSIsICJHQ1NLTy0yMCIsICJXVC0yMCIsICJHQ1NLTy1nbGFzZ293IiwgIkdDU0tPLTI4IiwgIkdDU0tPLTI5IiwgIkdDU0tPLW9vbSIsICJXVC04MjAiKSkKCiMjIG1ha2UgZXh0cmEgY29sdW1uIGZvciBwbG90dGluZyBhZXN0aGV0aWNzOgpkZl9zZXhfcmF0aW8kYWJvdmUgPC0gZGZfc2V4X3JhdGlvJHNleF9yYXRpb19sb2cgPiAxCgojIyBwbG90CmdncGxvdChkZl9zZXhfcmF0aW8sIGFlcyhzZXhfcmF0aW9fbG9nLCByZW9yZGVyKGdlbm90eXBlLCBzZXhfcmF0aW9fbG9nLCBzdW0pLCBjb2xvciA9IGFib3ZlKSkgKwogICAgICBnZW9tX3NlZ21lbnQoYWVzKHggPSAxLCB5ID0gZ2Vub3R5cGUsIHhlbmQgPSBzZXhfcmF0aW9fbG9nLCB5ZW5kID0gZ2Vub3R5cGUpLCBjb2xvciA9ICJncmV5NTAiKSArCiAgICAgIGdlb21fcG9pbnQoKSArCiAgICAgIGFubm90YXRlKCJyZWN0IiwgeG1pbj0gLTAuMzAxMDMwMDAsIHhtYXggPSAxLjAyMTE4OTMwLCB5bWluPS1JbmYgLCB5bWF4PUluZiwgYWxwaGE9MC4xLCBjb2xvcj1OQSxsaW5ldHlwZSA9IDIsIGZpbGw9ImJsdWUiKSArCiAgICAgICAgdGhlbWVfY2xhc3NpYygpCiAgCiMjIGh0dHBzOi8vdWMtci5naXRodWIuaW8vbG9sbGlwb3AKYGBgCgojIFNhdmUgey50YWJzZXR9CgpzYXZlIGNvdW50cyBhbmQgcGhlbm8gd2l0aG91dCBhbm9waGVsZXMgYW5kIGNvbnRyb2wgY2VsbHMKYGBge3J9CndyaXRlLmNzdihjb3VudHMsIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC9jb3VudHNfMjAyMF9maWx0ZXJlZC5jc3YiKQp3cml0ZS5jc3YocGhlbm8sIGZpbGUgPSAifi9kYXRhX3RvX2V4cG9ydC9waGVub18yMDIwX2ZpbHRlcmVkLmNzdiIpCmBgYAoKCmBgYHtyfQpwaGVub19maWx0ZXJlZF9jZWxscyA8LSBzczJfbXV0YW50c19maW5hbEBtZXRhLmRhdGEKY291bnRzX2ZpbHRlcmVkX2NlbGxzIDwtIHNzMl9tdXRhbnRzX2ZpbmFsQGFzc2F5cyRSTkFAY291bnRzCgp3cml0ZS5jc3YoY291bnRzX2ZpbHRlcmVkX2NlbGxzLCBmaWxlID0gIn4vZGF0YV90b19leHBvcnQvY291bnRzX2ZpbHRlcmVkX2NlbGxzLmNzdiIpCndyaXRlLmNzdihwaGVub19maWx0ZXJlZF9jZWxscywgZmlsZSA9ICJ+L2RhdGFfdG9fZXhwb3J0L3BoZW5vX2ZpbHRlcmVkX2NlbGxzLmNzdiIpCmBgYAoKc2F2ZSB0aGUgc2Vzc2lvbiBvYmplY3RzCmBgYHtyfQpzYXZlLmltYWdlKGZpbGUgPSAifi9HQ1NLT19TUzJfUUMuUkRhdGEiKQojbG9hZChmaWxlID0gIn4vR0NTS09fU1MyX1FDLlJEYXRhIikKCnNhdmUuaW1hZ2UoZmlsZSA9ICJ+L0dDU0tPX1NTMl9RQy5SRGF0YSIpCiNsb2FkKGZpbGUgPSAifi9HQ1NLT19TUzJfUUMuUkRhdGEiKQoKc2F2ZVJEUyhzczJfbXV0YW50c19maW5hbCwgZmlsZSA9ICJzczJfbXV0YW50c19maW5hbC5SRFMiKSAKI3NzMl9tdXRhbnRzX2ZpbmFsIDwtIHJlYWRSRFMoInNzMl9tdXRhbnRzX2ZpbmFsLlJEUyIpCgpgYGAKCgojIEFwcGVuZGl4IHsudGFic2V0fQoKIyMgU2Vzc2lvbiBJbmZvIApgYGB7ciwgZWNobyA9IEZBTFNFfQpzZXNzaW9uSW5mbygpCmBgYAoKIyMgRXh0cmFzCgojIyMgdGVzdGluZyBWaWthc2gncyBjZWxscwoKYGBge3J9CnZpa2FzaF9maWx0ZXJlZF9jZWxscyA8LSByZWFkLnRhYmxlKCJ+L2RhdGEvdmlrYXNoX2ZpbHRlcmVkX2NlbGxzXzIwXzAzXzI3LnR4dCIsIHNlcD0iXHQiLCBoZWFkZXIgPSBUUlVFKQpoZWFkKHZpa2FzaF9maWx0ZXJlZF9jZWxscykKYGBgCgpgYGB7cn0KdmlrYXNoX2tlZXBfY2VsbHMgPC0gdmlrYXNoX2ZpbHRlcmVkX2NlbGxzW3Zpa2FzaF9maWx0ZXJlZF9jZWxscyRmaW5hbF9jYWxsID09IDEsXSRYCgp0YWJsZSh2aWthc2hfZmlsdGVyZWRfY2VsbHMkZmluYWxfY2FsbCkKCnNzMl9tdXRhbnRzX2ZpbmFsCgp0YWJsZShyb3duYW1lcyhzczJfbXV0YW50c19maW5hbEBtZXRhLmRhdGEpICVpbiUgdmlrYXNoX2tlZXBfY2VsbHMpCmBgYAoKUUMgcGxvdCB3aXRoIHRoZXNlIG1ldHJpY3M6CmBgYHtyfQojIyBtYWtlIGRhdGFmcmFtZSBvZiBqdXN0IG1ldHJpY3MKY291bnRzX21ldHJpY3MgPC0gY291bnRzX2dlbmVzWy0oZ3JlcCgiUEJBTktBKiIsIHJvd25hbWVzKGNvdW50c19nZW5lcykpKSwgXQoKIyMgaW5zcGVjdApjb3VudHNfbWV0cmljc1sxOjUsMTo1XQoKIyMgdHJhbnNwb3NlIGRhdGFmcmFtZQpjb3VudHNfbWV0cmljc19wbG90IDwtIGFzLmRhdGEuZnJhbWUodChjb3VudHNfbWV0cmljcykpCgojIyBpbnNwZWN0CmNvdW50c19tZXRyaWNzX3Bsb3RbMTo1LDE6NV0KYGBgCgpwcmVwYXJlIHRoZSBkYXRhZnJhbWUgZm9yIHBsb3R0aW5nOgpgYGB7cn0KIyMgbWFrZSBhIGNvbHVtbiBmb3IgbmFtZSBvZiBjZWxsCmNvdW50c19tZXRyaWNzX3Bsb3QkY2VsbF9uYW1lIDwtIHJvd25hbWVzKGNvdW50c19tZXRyaWNzX3Bsb3QpCiMjIG9yZGVyIGJ5IGNvbHVtbgojY291bnRzX21ldHJpY3NfcGxvdCA8LSBjb3VudHNfbWV0cmljc19wbG90W29yZGVyKGNvdW50c19tZXRyaWNzX3Bsb3QkYF9fbm90X2FsaWduZWRgLCBkZWNyZWFzaW5nPVQpLF0KIyMgbWVsdApjb3VudHNfbWV0cmljc19wbG90IDwtIG1lbHQoY291bnRzX21ldHJpY3NfcGxvdCwgaWQudmFycyA9ICJjZWxsX25hbWUiKQojIyBjb3VudCBudW1iZXIgb2YgemVybyB2YWx1ZXM6Cmxlbmd0aCh3aGljaChjb3VudHNfbWV0cmljc19wbG90JHZhbHVlID09IDApKQojIyBsb2cgdGhlIHZhbHVlCmNvdW50c19tZXRyaWNzX3Bsb3QkdmFsdWUgPC0gbG9nKGNvdW50c19tZXRyaWNzX3Bsb3QkdmFsdWUgKyAxLCAxMCkKYGBgCgpgYGB7cn0KI21lbHRSJGV4cGVyaW1lbnQgPC0gZmFjdG9yKG1lbHRSJGV4cGVyaW1lbnQsIGxldmVscyA9IG1lbHRSJGV4cGVyaW1lbnRbb3JkZXIoLW1lbHRSJHZhbHVlW21lbHRSJHZhcmlhYmxlID09IGxldl0pXSkKIyMgcmVvcmRlciBiYXNlZCBvbiBvbmUgbWV0cmljIChuYW1lbHkgbm90IG1hcHBlZCBoZXJlKQpjb3VudHNfbWV0cmljc19wbG90JGNlbGxfbmFtZSA8LSBmYWN0b3IoY291bnRzX21ldHJpY3NfcGxvdCRjZWxsX25hbWUsIGxldmVscyA9IGNvdW50c19tZXRyaWNzX3Bsb3QkY2VsbF9uYW1lW29yZGVyKC1jb3VudHNfbWV0cmljc19wbG90JHZhbHVlW2NvdW50c19tZXRyaWNzX3Bsb3QkdmFyaWFibGUgPT0gbGV2ZWxzKGNvdW50c19tZXRyaWNzX3Bsb3QkdmFyaWFibGUpWzRdXSldKQogICAgCiMjIHRvIHJlb3JkZXIganVzdCBiYXNlZCBvbiBzdW06CiNnZ3Bsb3QoY291bnRzX21ldHJpY3NfcGxvdCwgYWVzKGZpbGw9dmFyaWFibGUsIHk9dmFsdWUsIHg9cmVvcmRlcihjZWxsX25hbWUsIHZhbHVlLCBzdW0pKSkgKyAKIyAgICBnZW9tX2Jhcihwb3NpdGlvbj0ic3RhY2siLCBzdGF0PSJpZGVudGl0eSIpCgojIyByZWY6IGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzQwMDIwMzg2L3Jlb3JkZXItYWNjb3JkaW5nLXZhcmlhYmxlLW9mLW1lbHRlZC1kYXRhZnJhbWUgCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDEwLCBmaWcuaGVpZ2h0ID0gNX0KIyMgcGxvdApnZ3Bsb3QoY291bnRzX21ldHJpY3NfcGxvdCwgYWVzKGZpbGw9dmFyaWFibGUsIHk9dmFsdWUsIHg9Y2VsbF9uYW1lKSkgKyAKICBnZW9tX2Jhcihwb3NpdGlvbj0ic3RhY2siLCBzdGF0PSJpZGVudGl0eSIpICsKICAjIGxhYmVsIHBsb3QKICBsYWJzKHggPSAiQ2VsbHMiLCB5ID0gImxvZzEwKG51bWJlciBvZiByZWFkcykiKSArCiAgIyByZW1vdmUgdGhlIHggYXhpcwogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMubGluZS54ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCnBsb3Qgd2l0aCBtYXBwZWQgc3RhdGlzdGljczoKYGBge3J9CiMjIG1ha2UgYSBkYXRhZnJhbWUgb2YgYWxsIG1hcHBlZCByZWFkcwptYXBwZWRfcmVhZHMgPC0gYXMuZGF0YS5mcmFtZShjb2xTdW1zKGNvdW50cykpCiMjIHRyYW5zcG9zZSB0aGUgbWV0cmljcyBmb3IgbWVyZ2luZwpjb3VudHNfbWV0cmljc19mdWxsIDwtIGFzLmRhdGEuZnJhbWUodChjb3VudHNfbWV0cmljcykpCiMjIGNoZWNrIHRoYXQgdGhlIHJvd25hbWVzIGFyZSBpZGVudGljYWwKI2lkZW50aWNhbChyb3duYW1lcyhjb3VudHNfbWV0cmljc19mdWxsKSwgcm93bmFtZXMobWFwcGVkX3JlYWRzKSkKIyMgYmluZCB0aGUgZGF0YWZyYW1lcyB0b2dldGhlcgpjb3VudHNfbWV0cmljc19mdWxsIDwtIGNiaW5kKGNvdW50c19tZXRyaWNzX2Z1bGwsIG1hcHBlZF9yZWFkcykKIyMgbWFrZSBhIGNvbHVtbiBmb3IgY2VsbCBuYW1lCmNvdW50c19tZXRyaWNzX2Z1bGwkY2VsbF9uYW1lIDwtIHJvd25hbWVzKGNvdW50c19tZXRyaWNzX2Z1bGwpCiMjIG1lbHQKY291bnRzX21ldHJpY3NfZnVsbCA8LSBtZWx0KGNvdW50c19tZXRyaWNzX2Z1bGwsIGlkLnZhcnMgPSAiY2VsbF9uYW1lIikKIyMgY291bnQgbnVtYmVyIG9mIHplcm8gdmFsdWVzOgpsZW5ndGgod2hpY2goY291bnRzX21ldHJpY3NfZnVsbCR2YWx1ZSA9PSAwKSkKIyMgbG9nIHRoZSB2YWx1ZQpjb3VudHNfbWV0cmljc19mdWxsJHZhbHVlIDwtIGxvZyhjb3VudHNfbWV0cmljc19mdWxsJHZhbHVlICsgMSwgMTApCmBgYApwbG90OgpgYGB7ciwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA1fQojIyBwbG90CmdncGxvdChjb3VudHNfbWV0cmljc19mdWxsLCBhZXMoZmlsbD12YXJpYWJsZSwgeT12YWx1ZSwgeD1yZW9yZGVyKGNlbGxfbmFtZSwgdmFsdWUsIHN1bSkpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uPSJzdGFjayIsIHN0YXQ9ImlkZW50aXR5IikgKwogICMgbGFiZWwgcGxvdAogIGxhYnMoeCA9ICJDZWxscyIsIHkgPSAibG9nMTAobnVtYmVyIG9mIHJlYWRzKSIpICsKICAjIHJlbW92ZSB0aGUgeCBheGlzCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKKioqCiMjIDMuIEFuYWx5c2lzCgojIyMgTGlnaHQgZmlsdGVyCmBgYHtyfQpzczJfbXV0YW50c19maWx0ZXJlZCA8LSBzdWJzZXQoc3MyX211dGFudHMsIHN1YnNldCA9IG5GZWF0dXJlX1JOQSA+IDQwICYgbkZlYXR1cmVfUk5BIDwgNTI0NiAmIHBlcmNlbnQubXQgPCAxMDEgJiBuQ291bnRfUk5BID4gMTAwMCkKc3MyX211dGFudHNfZmlsdGVyZWQKYGBgCgo0MzU4IC0gMzY0MCA9IDcxOCBjZWxscyB3ZXJlIHJlbW92ZWQgYnkgdGhpcyB2ZXJ5IGxpZ2h0IGZpbHRlcgoKZmlsdGVyIGdlbmVzCmBgYHtyfQojIyBob3cgbWFueSBnZW5lcyBhcmUgbm90IGRldGVjdGVkIGF0IGFsbCBub3cgdGhhdCBpdCBpcyBmaWx0ZXJlZCBvZiBiYWQgY2VsbHM/Cmxlbmd0aCh3aGljaChyb3dTdW1zKHNzMl9tdXRhbnRzX2ZpbHRlcmVkQGFzc2F5cyRSTkFAY291bnRzKSA9PSAwKSkKYGBgCgojIyBGaWx0ZXJlZCBPYmplY3QKCm5vcm1hbGlzZSBhbmQgZmluZCB2YXJpYWJsZSBnZW5lcwpgYGB7cn0KIyMgbm9ybWFsaXNlCnNzMl9tdXRhbnRzX2ZpbHRlcmVkIDwtIE5vcm1hbGl6ZURhdGEoc3MyX211dGFudHNfZmlsdGVyZWQsIG5vcm1hbGl6YXRpb24ubWV0aG9kID0gIkxvZ05vcm1hbGl6ZSIsIHNjYWxlLmZhY3RvciA9IDEwMDAwKQojIyBmaW5kIHZhcmlhYmxlIGdlbmVzCnNzMl9tdXRhbnRzX2ZpbHRlcmVkIDwtIEZpbmRWYXJpYWJsZUZlYXR1cmVzKHNzMl9tdXRhbnRzX2ZpbHRlcmVkLCBzZWxlY3Rpb24ubWV0aG9kID0gInZzdCIsIG5mZWF0dXJlcyA9IDIwMDApCiMjIG1ha2UgYSBsaXN0IG9mIGFsbCBnZW5lcyBpbiB0aGUgZGF0YXNldAphbGwuZ2VuZXMgPC0gcm93bmFtZXMoc3MyX211dGFudHNfZmlsdGVyZWQpCiMjIHNjYWxlIGRhdGEgb24gYWxsIGdlbmVzCnNzMl9tdXRhbnRzX2ZpbHRlcmVkIDwtIFNjYWxlRGF0YShzczJfbXV0YW50c19maWx0ZXJlZCwgZmVhdHVyZXMgPSBhbGwuZ2VuZXMpCmBgYAoKIyMgcGxvdAoKYGBge3J9CnNzMl9tdXRhbnRzX2ZpbHRlcmVkIDwtIFJ1blBDQShzczJfbXV0YW50c19maWx0ZXJlZCwgZmVhdHVyZXMgPSBWYXJpYWJsZUZlYXR1cmVzKG9iamVjdCA9IHNzMl9tdXRhbnRzX2ZpbHRlcmVkKSkKYGBgCgpgYGB7cn0KRGltUGxvdChzczJfbXV0YW50c19maWx0ZXJlZCwgcmVkdWN0aW9uID0gInBjYSIpCmBgYAoKYGBge3J9CkVsYm93UGxvdChzczJfbXV0YW50c19maWx0ZXJlZCwgbmRpbXMgPSAzMCwgcmVkdWN0aW9uID0gInBjYSIpCmBgYAoKYGBge3J9CnNzMl9tdXRhbnRzX2ZpbHRlcmVkIDwtIEZpbmROZWlnaGJvcnMoc3MyX211dGFudHNfZmlsdGVyZWQsIGRpbXMgPSAxOjIxKQpzczJfbXV0YW50c19maWx0ZXJlZCA8LSBGaW5kQ2x1c3RlcnMoc3MyX211dGFudHNfZmlsdGVyZWQsIHJlc29sdXRpb24gPSAxKQpgYGAKCmBgYHtyfQpzczJfbXV0YW50c19maWx0ZXJlZCA8LSBSdW5VTUFQKHNzMl9tdXRhbnRzX2ZpbHRlcmVkLCBkaW1zID0gMToyMSkKYGBgCgpgYGB7cn0KRGltUGxvdChzczJfbXV0YW50c19maWx0ZXJlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJpZGVudCIsIGxhYmVsID0gVFJVRSkKYGBgCgpgYGB7cn0KRGltUGxvdChzczJfbXV0YW50c19maWx0ZXJlZCwgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJpZGVudGl0eV91cGRhdGVkIikKYGBgCmBgYHtyfQpzczJfbXV0YW50c19maWx0ZXJlZCA8LSBBZGRNZXRhRGF0YShzczJfbXV0YW50c19maWx0ZXJlZCwgbG9nMTAoc3MyX211dGFudHNfZmlsdGVyZWRAbWV0YS5kYXRhJG5Db3VudF9STkEpLCBjb2wubmFtZSA9ICJuQ291bnRfbG9nMTAiKQoKRmVhdHVyZVBsb3Qoc3MyX211dGFudHNfZmlsdGVyZWQsIGZlYXR1cmVzID0gYygibkNvdW50X1JOQSIsICJuQ291bnRfbG9nMTAiLCAibkZlYXR1cmVfUk5BIiwgInBlcmNlbnQubXQiKSwgcmVkdWN0aW9uID0gInVtYXAiKSAgIApgYGAKCmludGVyYWN0aXZlCmBgYHtyfQpwbG90IDwtIEZlYXR1cmVQbG90KHNzMl9tdXRhbnRzX2ZpbHRlcmVkLCBmZWF0dXJlcyA9ICJuRmVhdHVyZV9STkEiLCByZWR1Y3Rpb24gPSAidW1hcCIpICAgCgpIb3ZlckxvY2F0b3IocGxvdCA9IHBsb3QsIGluZm9ybWF0aW9uID0gRmV0Y2hEYXRhKHNzMl9tdXRhbnRzX2ZpbHRlcmVkLCB2YXJzID0gYygibkZlYXR1cmVfUk5BIiwgImlkZW50IiwgImlkZW50aXR5X3VwZGF0ZWQiKSkpCmBgYAoKbG9vayBhdCB0aGlzIG9uIGEgY2x1c3Rlci1ieS1jbHVzdGVyIGJhc2lzOgpgYGB7cn0KVmxuUGxvdChvYmplY3QgPSBzczJfbXV0YW50c19maWx0ZXJlZCwgZmVhdHVyZXMgPSAibkZlYXR1cmVfUk5BIiwgcHQuc2l6ZSA9IDAuMDEpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0PTI1MCkKYGBgCgpgYGB7cn0KVmxuUGxvdChvYmplY3QgPSBzczJfbXV0YW50c19maWx0ZXJlZCwgZmVhdHVyZXMgPSAibkNvdW50X2xvZzEwIiwgcHQuc2l6ZSA9IDAuMDEpCmBgYAoKYGBge3J9ClZsblBsb3Qob2JqZWN0ID0gc3MyX211dGFudHNfZmlsdGVyZWQsIGZlYXR1cmVzID0gInBlcmNlbnQubXQiLCBwdC5zaXplID0gMC4wMSkgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9MjApCmBgYAoKYGBge3J9CmNsdXN0ZXJfZm91cl9jZWxsc19kZiA8LSBzczJfbXV0YW50c19maWx0ZXJlZEBtZXRhLmRhdGFbKHNzMl9tdXRhbnRzX2ZpbHRlcmVkQG1ldGEuZGF0YSRzZXVyYXRfY2x1c3RlcnMgPT0gNCksXQoKZ2dwbG90KGNsdXN0ZXJfZm91cl9jZWxsc19kZiwgYWVzKHggPSBwZXJjZW50Lm10LCB5ID0gbkZlYXR1cmVfUk5BKSkgKyBnZW9tX3BvaW50KHNpemUgPSAxKQoKI0ZlYXR1cmVTY2F0dGVyKHNzMl9tdXRhbnRzX2ZpbHRlcmVkLCBmZWF0dXJlMSA9ICJwZXJjZW50Lm10IiwgZmVhdHVyZTIgPSAibkZlYXR1cmVfUk5BIiwgY2VsbHMgPSAsIHB0LnNpemUgPSAwLjAxLCBncm91cC5ieSA9ICJleHBlcmltZW50IikKYGBgCgoKaWRlbml0Znkgd2hpY2ggY2x1c3RlcnMgYXJlIHdoaWNoCgpgYGB7ciwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDh9CiMgUEJBTktBLTA1MTUwMDAgLSBwMjUgLSBmZW1hbGUKIyBQQkFOS0EtMTMxOTUwMCAtIENDUDIgLSBmZW1hbGUgLSB1c2VkIGluIDgyMCBsaW5lCiMgUEJBTktBLTEyMTI2MDAgLSBIQVAyIC0gbWFsZQojIFBCQU5LQS0wNjAwNjAwIC0gTkVLMyAtIG1hbGUKIyBQQkFOS0EtMTMxNTcwMCAtIFJPTjIgLSAoYXNleHVhbHMgYW5kIHNvbWUgbWFsZT8pCiMgUEJBTktBLTA0MTYxMDAgLSBkeW5lbmluIGhlYXZ5IGNoYWluIC0gbWFsZSAtIHVzZWQgaW4gODIwIGxpbmUKIyBQQkFOS0EtMTQzNzUwMCAtIEFQMi1HIC0gc2V1eGFsIGNvbW1pdG1lbnQgZ2VuZQojIFBCQU5LQS0wODMxMDAwIC0gTVNQMSAtIGxhdGUgYXNleHVhbAojIFBCQU5LQS0xMTAyMjAwIC0gTVNQOCAtIGVhcmx5IGFzZXh1YWwgKGZyb20gQm96ZGVjaCBwYXBlcikKRmVhdHVyZVBsb3Qoc3MyX211dGFudHNfZmlsdGVyZWQsIGZlYXR1cmVzID0gYygiUEJBTktBLTA1MTUwMDAiLCAiUEJBTktBLTEzMTk1MDAiLCAiUEJBTktBLTEyMTI2MDAiLCJQQkFOS0EtMDYwMDYwMCIsICJQQkFOS0EtMTMxNTcwMCIsICJQQkFOS0EtMDQxNjEwMCIsICJQQkFOS0EtMTQzNzUwMCIsICJQQkFOS0EtMDgzMTAwMCIsICJQQkFOS0EtMTEwMjIwMCIpLCBjb29yZC5maXhlZCA9IFRSVUUpCmBgYAoKcHJlcCBmb3IgZG90cGxvdApgYGB7cn0KZGZfbWV0YV9kYXRhIDwtIGFzLmRhdGEuZnJhbWUoc3MyX211dGFudHNfZmlsdGVyZWRAbWV0YS5kYXRhKQoKZG90X3Bsb3RfZGYgPC0gYXMuZGF0YS5mcmFtZS5tYXRyaXgodGFibGUoZGZfbWV0YV9kYXRhJFJOQV9zbm5fcmVzLjEsIGRmX21ldGFfZGF0YSRpZGVudGl0eV91cGRhdGVkKSkKCmRvdF9wbG90X2RmX3BjIDwtIChhcy5kYXRhLmZyYW1lLm1hdHJpeChwcm9wLnRhYmxlKHRhYmxlKGRmX21ldGFfZGF0YSRSTkFfc25uX3Jlcy4xLCBkZl9tZXRhX2RhdGEkaWRlbnRpdHlfdXBkYXRlZCksIG1hcmdpbiA9IDIpKSAqIDEwMCkKCmRvdF9wbG90X2RmX3BjJGNsdXN0ZXIgPC0gcm93bmFtZXMoZG90X3Bsb3RfZGZfcGMpCmxpYnJhcnkoZHBseXIpCmRvdF9wbG90X2RmX3BjX211dGF0ZWQgPC0gbXV0YXRlKGRvdF9wbG90X2RmX3BjKQpsaWJyYXJ5KHJlc2hhcGUyKQpkb3RfcGxvdF9kZl9wY19tZWx0ZWQgPC0gbWVsdChkb3RfcGxvdF9kZl9wYywgdmFyaWFibGUubmFtZSA9ICJjbHVzdGVyIikKY29sbmFtZXMoZG90X3Bsb3RfZGZfcGNfbWVsdGVkKVsyXSA8LSAiaWRlbnRpdHkiCmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDYsIGZpZy5oZWlnaHQ9IDd9CmxpYnJhcnkoZ2dwbG90MikKICBwID0gZ2dwbG90KGRvdF9wbG90X2RmX3BjX21lbHRlZCwKICAgICAgICAgICAgIGFlcyh5ID0gZmFjdG9yKGNsdXN0ZXIpLAogICAgICAgICAgICAgICAgIHggPSBmYWN0b3IoaWRlbnRpdHkpKSkgKwogICAgICBnZW9tX3BvaW50KGFlcyhjb2xvdXI9dmFsdWUsIHNpemU9dmFsdWUpKSArIAogICAgICBzY2FsZV9jb2xvcl9ncmFkaWVudChsb3c9ImJsdWUiLCBoaWdoPSJyZWQiLCBsaW1pdHM9YyggMSwgbWF4KGRvdF9wbG90X2RmX3BjX21lbHRlZCR2YWx1ZSkpKSArCiAgICAgIHRoZW1lX2J3KCkgKwogICAgICB0aGVtZShwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCkpCiAgcCA9IHAgKwogICAgICB5bGFiKCJDbHVzdGVyIikgKwogICAgICB4bGFiKCJJZGVudGl0eSIpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MTIsIGZhY2U9Iml0YWxpYyIsIGFuZ2xlPTQ1LCBoanVzdD0xKSkgKyAKICAgICAgdGhlbWUoYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9MTIsIGZhY2U9Iml0YWxpYyIpKQogIHByaW50KHApCmBgYAoKIyMjIyBPbGQgd2F5IG9mIHBsb3R0aW5nIG1pY3JvdGl0cmUgcGxhdGVzCgpUaGUgcHJldmlvdXMgd2F5IG9mIHBsb3R0aW5nIHBsYXRlcyBicm9rZS4gCgpUaGUgcGFja2FnZXMgaW52b2x2ZWQgYXJlOgpnZ3Bsb3QyIDMuMi4xICh3ZWIgaW5zdGFuY2UpIHZzIDMuMy4yIChoZXJlKQpnZ3Bsb3QyYmRjIDAuMy4yICh3ZWIgaW5zdGFuY2UpIHZzLiAwLjMuMiAoaGVyZSkgCgpTb21ldGhpbmcgaGFwcGVuZWQgaW4gdGhlIGdncGxvdDIgdXBkYXRlIHRoYXQgbWVhbnQgdGhlIHRpdGxlIGFuZCBndWlkZXMgd2VyZSBzdXBlcmltcG9zZWQgb24gdGhlIHBsb3QuIFRoZSBzcGVjaWZpYyBpc3N1ZSB3YXMgd2l0aCB0aGUgc2NhbGVfeV9yZXZlcnNlKCkgZnVuY3Rpb24uCgpgYGB7cn0Kc2FtcGxlX21hcCA8LSBnZ3Bsb3QoZGF0YT10YWJsZV9wbGF0ZW1hcCwgYWVzKHg9Q29sdW1uLCB5PVJvdykpICsKICAjc2V0IHVwIHRoZSBwbGF0ZW1hcCBsYXlvdXQKICAgIGdlb21fcG9pbnQoZGF0YT1leHBhbmQuZ3JpZChzZXEoMSwgMTIpLCBzZXEoMSwgOCkpLCBhZXMoeD1WYXIxLCB5PVZhcjIpLCBjb2xvcj0iZ3JleTkwIiwgZmlsbD0id2hpdGUiLCBzaGFwZT0yMSwgc2l6ZT02KSArCiAgI0NoYW5nZSB0aGUgc2hhcGUgYW5kIGNvbG91ciBvZiBwb2ludHMgZm9yIGEgdmFyaWFibGUKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBmaWx0ZXJlZF9wYykpICsKICAjY2hhbmdlIHRoZSBjb2xvdXJzCiAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfYyhndWlkZSA9ICJjb2xvdXJiYXIiLCBuYS52YWx1ZT0id2hpdGUiKSArCiAgI2ZpeCB0aGUgcmF0aW8gb2YgY29vcmRpbmF0ZXMKICAgIGNvb3JkX2ZpeGVkKHJhdGlvPSgxMy8xMikvKDkvOCksIHhsaW09YygwLjUsIDEyLjUpLCB5bGltPWMoMC41LCA4LjUpKSArCiAgI2FkZCBsYWJlbHMgZm9yIHRoZSB5IGF4aXMKICAgIHNjYWxlX3lfcmV2ZXJzZShicmVha3M9c2VxKDEsIDgpLCBsYWJlbHM9TEVUVEVSU1sxOjhdKSArCiAgI2FkZCBsYWJlbHMgZm9yIHRoZSB4IGF4aXMKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKDEsIDEyKSkgKwogICNBZGQgYSB0aXRsZQogICAgbGFicyh0aXRsZT0iVGhlIHBvc2l0aW9uIG9mIGNlbGxzIHRoYXQgZmFpbGVkIFFDIiAsIHNpemUgPSA2LCBjb2xvdXIgPSAicGVyY2VudGFnZSBvZiBjZWxscyBpbiB0aGlzIHdlbGwgdGhhdCBmYWlsZWQgUUMiKSArCiAgI3JvdGF0ZSBsZWdlbmQgZ3VpZGUgYmVjYXVzZSBvdGhlcndpc2UgeW91IGNhbid0IHNlZSBudW1iZXJzOgogICAgZ3VpZGVzKGZpbGwgPSBndWlkZV9jb2xvcmJhcihiYXJ3aWR0aCA9IDAuNSwgYmFyaGVpZ2h0ID0gMTAsIHRpdGxlPSJWYWx1ZSIpKSArCiAgI2NoYW5nZSB0aGUgY29sb3VycwogICAgI3NjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiSG9lY2hzdCI9ImJsdWUiLCAiSG9lc2NodCIgPSAiYmx1ZSIsICJtQ2hlcnJ5Ij0icmVkIiwgIkdGUCI9ImdyZWVuIikpICsKICAjIG1ha2UgbWltbmltdW0gcG9pbnQgc2l6ZSBiaWdnZXIKICAgICNzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDIsMTApKSArCiAgIyBtYWtlIGludG8gYSBwbGF0ZSBwbG90CiAgICB0aGVtZV9iZGNfbWljcm90aXRlcigpCgpzYW1wbGVfbWFwCmBgYAoKCg==